Skip to content

Commit

Permalink
feat: Add enterDelay and leaveDelay props (#14)
Browse files Browse the repository at this point in the history
* feat: Add enterDelay and leaveDelay props, #10

* fix: Fix position className assignation, #10
  • Loading branch information
untemps committed Jan 30, 2022
1 parent ece5c6b commit b660877
Show file tree
Hide file tree
Showing 6 changed files with 320 additions and 153 deletions.
30 changes: 17 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ yarn add @untemps/svelte-use-tooltip
position: 'right',
animated: true,
animationEnterClassName: 'tooltip-enter',
animationLeaveClassName: 'tooltip-leave',
animationLeaveClassName: 'tooltip-leave',
enterDelay: 200,
leaveDelay: 400,
disabled: false
}
} class="tooltip__target">
Expand Down Expand Up @@ -102,18 +104,20 @@ yarn add @untemps/svelte-use-tooltip

## API

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

### Content Actions

Expand Down
30 changes: 23 additions & 7 deletions dev/src/App.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<script>
import { useTooltip } from '../../src'
let textContent = null
let tooltipTextContent = null
let useCustomTooltipClass = false
let tooltipPosition = 'top'
let isTooltipDisabled = false
let animateTooltip = false
let useCustomAnimationEnterClass = false
let useCustomAnimationLeaveClass = false
let tooltipEnterDelay = 200
let tooltipLeaveDelay = 200
const _onTooltipClick = (arg) => {
console.log(arg)
Expand All @@ -19,8 +21,8 @@
<div
use:useTooltip={{
position: tooltipPosition,
content: textContent,
contentSelector: !textContent?.length ? '.tooltip__content' : null,
content: tooltipTextContent,
contentSelector: !tooltipTextContent?.length ? '.tooltip__content' : null,
contentClone: true,
contentActions: {
'*': {
Expand All @@ -31,10 +33,12 @@
},
},
containerClassName: useCustomTooltipClass ? 'tooltip' : null,
disabled: isTooltipDisabled,
animated: animateTooltip,
animationEnterClassName: useCustomAnimationEnterClass ? 'tooltip-enter' : null,
animationLeaveClassName: useCustomAnimationLeaveClass ? 'tooltip-leave' : null,
enterDelay: tooltipEnterDelay,
leaveDelay: tooltipLeaveDelay,
disabled: isTooltipDisabled
}}
class="target"
>
Expand All @@ -51,7 +55,7 @@
<fieldset>
<label>
Tooltip Text Content:
<input type="text" bind:value={textContent} />
<input type="text" bind:value={tooltipTextContent} />
</label>
</fieldset>
<fieldset>
Expand Down Expand Up @@ -79,16 +83,28 @@
</fieldset>
<fieldset>
<label>
Use Custom Animation Enter Class:
Use Custom Tooltip Animation Enter Class:
<input type="checkbox" bind:checked={useCustomAnimationEnterClass} />
</label>
</fieldset>
<fieldset>
<label>
Use Custom Animation Leave Class:
Use Custom Tooltip Animation Leave Class:
<input type="checkbox" bind:checked={useCustomAnimationLeaveClass} />
</label>
</fieldset>
<fieldset>
<label>
Tooltip Enter Delay (ms):
<input type="number" step={100} min={0} bind:value={tooltipEnterDelay} />
</label>
</fieldset>
<fieldset>
<label>
Tooltip Leave Delay (ms):
<input type="number" step={100} min={0} bind:value={tooltipLeaveDelay} />
</label>
</fieldset>
<fieldset>
<label>
Disable Tooltip:
Expand Down
7 changes: 4 additions & 3 deletions jest/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import '@testing-library/jest-dom/extend-expect'

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

global._createElement = (id = 'foo', className = 'bar', ariaLabel = 'gag') => {
global._createElement = (id = 'foo', attrs) => {
const el = document.createElement('div')
el.setAttribute('id', id)
el.setAttribute('class', className)
el.setAttribute('aria-label', ariaLabel)
for (let key in attrs) {
el.setAttribute(key, attrs[key])
}
document.body.appendChild(el)
return el
}
Expand Down
55 changes: 46 additions & 9 deletions src/Tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Tooltip {

#observer = null
#events = []
#enterDelay = 0
#leaveDelay = 0
#delay = null

#tooltip = null

Expand Down Expand Up @@ -44,25 +47,30 @@ class Tooltip {
animated,
animationEnterClassName,
animationLeaveClassName,
enterDelay,
leaveDelay,
disabled
) {
this.#target = target
this.#content = content
this.#contentSelector = contentSelector
this.#contentClone = contentClone || false
this.#contentActions = contentActions
this.#contentClone = contentClone
this.#containerClassName = containerClassName
this.#position = position
this.#animated = animated
this.#position = position || 'top'
this.#animated = animated || false
this.#animationEnterClassName = animationEnterClassName || '__tooltip-enter'
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
this.#enterDelay = enterDelay || 0
this.#leaveDelay = leaveDelay || 0

this.#observer = new DOMObserver()

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

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

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

Expand All @@ -79,31 +87,41 @@ class Tooltip {
animated,
animationEnterClassName,
animationLeaveClassName,
enterDelay,
leaveDelay,
disabled
) {
const hasContentChanged = contentSelector !== this.#contentSelector || content !== this.#content
const hasContainerClassNameChanged = containerClassName !== this.#containerClassName
const oldPosition = this.#position
const hasPositionChanged = position !== this.#position
const hasToDisableTarget = disabled && this.#boundEnterHandler
const hasToEnableTarget = !disabled && !this.#boundEnterHandler

this.#content = content
this.#contentSelector = contentSelector
this.#contentClone = contentClone
this.#contentClone = contentClone || false
this.#contentActions = contentActions
this.#containerClassName = containerClassName
this.#position = position
this.#animated = animated
this.#position = position || 'top'
this.#animated = animated || false
this.#animationEnterClassName = animationEnterClassName || '__tooltip-enter'
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
this.#enterDelay = enterDelay || 0
this.#leaveDelay = leaveDelay || 0

if (hasContentChanged) {
this.#removeTooltipFromTarget()

this.#createTooltip()
}

if (hasContainerClassNameChanged) {
this.#tooltip.className = this.#containerClassName || `__tooltip __tooltip-${this.#position}`
this.#tooltip.classList.add(this.#containerClassName || '__tooltip')
}

if (hasPositionChanged) {
this.#tooltip.classList.remove(`__tooltip-${oldPosition}`)
this.#tooltip.classList.add(`__tooltip-${this.#position}`)
}

if (hasToDisableTarget) {
Expand All @@ -118,6 +136,8 @@ class Tooltip {

this.#disableTarget()

this.#clearDelay()

this.#observer?.clear()
this.#observer = null
}
Expand All @@ -140,7 +160,6 @@ class Tooltip {

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

if (this.#contentSelector) {
this.#observer
Expand Down Expand Up @@ -229,6 +248,22 @@ class Tooltip {
this.#events = []
}

#waitForDelay(delay) {
this.#clearDelay()
return new Promise(
(resolve) =>
(this.#delay = setTimeout(() => {
this.#clearDelay()
resolve()
}, delay))
)
}

#clearDelay() {
clearTimeout(this.#delay)
this.#delay = null
}

#transitionTooltip(direction) {
return new Promise((resolve) => {
let classToAdd, classToRemove
Expand Down Expand Up @@ -260,10 +295,12 @@ class Tooltip {
}

async #onTargetEnter() {
await this.#waitForDelay(this.#enterDelay)
await this.#appendTooltipToTarget()
}

async #onTargetLeave() {
await this.#waitForDelay(this.#leaveDelay)
await this.#removeTooltipFromTarget()
}
}
Expand Down
Loading

0 comments on commit b660877

Please sign in to comment.