Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,20 +138,22 @@ 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. |
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). |
| `containerClassName` | string | '__tooltip' | 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 | '__tooltip-enter' | Class name to apply to the tooltip enter transition. |
| `animationLeaveClassName` | string | '__tooltip-leave' | Class name to apply to the tooltip leave transition. |
| `enterDelay` | number | 0 | Delay before showing the tooltip in milliseconds. |
| `leaveDelay` | number | 0 | Delay before hiding the tooltip in milliseconds. |
| `offset` | number | 10 | Distance between the tooltip and the target in pixels. |
| `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. |
| `contentActions` | object | null | Configuration of the tooltip actions (see [Content Actions](#content-actions)). |
| `containerClassName` | string | '__tooltip' | 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 | '__tooltip-enter' | Class name to apply to the tooltip enter transition. |
| `animationLeaveClassName` | string | '__tooltip-leave' | Class name to apply to the tooltip leave transition. |
| `enterDelay` | number | 0 | Delay before showing the tooltip in milliseconds. |
| `leaveDelay` | number | 0 | Delay before hiding the tooltip in milliseconds. |
| `onEnter` | func | null | Callback triggered when the tooltip appears. |
| `onLeave` | func | null | Callback triggered when the tooltip disappears. |
| `offset` | number | 10 | Distance between the tooltip and the target in pixels. |
| `disabled` | boolean | false | Flag to disable the tooltip content. |

### Content and Content Selector

Expand Down
98 changes: 63 additions & 35 deletions dev/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,30 @@

let showSettings = false

let tooltipTextContent = null
let useCustomTooltipClass = false
let tooltipPosition = 'top'
let isTooltipDisabled = false
let animateTooltip = false
let textContent = null
let useCustomClass = false
let position = 'top'
let isDisabled = false
let animate = false
let useCustomAnimationEnterClass = false
let useCustomAnimationLeaveClass = false
let tooltipEnterDelay = 200
let tooltipLeaveDelay = 200
let tooltipOffset = 10
let enterDelay = 200
let leaveDelay = 200
let triggerOnEnter = false
let triggerOnLeave = false
let offset = 10

const _onTooltipEnter = () => {
if(triggerOnEnter) {
alert('You\'ve entered the target')
}
}

const _onTooltipLeave = () => {
if(triggerOnLeave) {
alert('You\'ve left the target')
}
}

const _onTooltipClick = (arg, e) => {
e.preventDefault()
Expand Down Expand Up @@ -204,20 +218,20 @@
<form class="settings__form">
<fieldset>
<label>
Tooltip Text Content:
<input type="text" bind:value={tooltipTextContent}/>
Text Content:
<input type="text" bind:value={textContent}/>
</label>
</fieldset>
<fieldset>
<label>
Use Custom Tooltip Class:
<input type="checkbox" bind:checked={useCustomTooltipClass}/>
Use Custom Class:
<input type="checkbox" bind:checked={useCustomClass}/>
</label>
</fieldset>
<fieldset>
<label>
Tooltip Position:
<select bind:value={tooltipPosition}>
Position:
<select bind:value={position}>
<option value="left">Left</option>
<option value="right">Right</option>
<option value="top">Top</option>
Expand All @@ -227,44 +241,56 @@
</fieldset>
<fieldset>
<label>
Animate tooltip:
<input type="checkbox" bind:checked={animateTooltip}/>
Animate:
<input type="checkbox" bind:checked={animate}/>
</label>
</fieldset>
<fieldset>
<label>
Use Custom Tooltip Animation Enter Class:
Use Custom Animation Enter Class:
<input type="checkbox" bind:checked={useCustomAnimationEnterClass}/>
</label>
</fieldset>
<fieldset>
<label>
Use Custom Tooltip Animation Leave Class:
Use Custom 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}/>
Enter Delay (ms):
<input type="number" step={100} min={0} bind:value={enterDelay}/>
</label>
</fieldset>
<fieldset>
<label>
Leave Delay (ms):
<input type="number" step={100} min={0} bind:value={leaveDelay}/>
</label>
</fieldset>
<fieldset>
<label>
Trigger callback on enter:
<input type="checkbox" bind:checked={triggerOnEnter}/>
</label>
</fieldset>
<fieldset>
<label>
Tooltip Leave Delay (ms):
<input type="number" step={100} min={0} bind:value={tooltipLeaveDelay}/>
Trigger callback on leave:
<input type="checkbox" bind:checked={triggerOnLeave}/>
</label>
</fieldset>
<fieldset>
<label>
Tooltip Offset (px):
<input type="number" step={1} min={5} bind:value={tooltipOffset}/>
Offset (px):
<input type="number" step={1} min={5} bind:value={offset}/>
</label>
</fieldset>
<fieldset>
<label>
Disable Tooltip:
<input type="checkbox" bind:checked={isTooltipDisabled}/>
Disable:
<input type="checkbox" bind:checked={isDisabled}/>
</label>
</fieldset>
</form>
Expand All @@ -276,9 +302,9 @@
</button>
<div
use:useTooltip={{
position: tooltipPosition,
content: tooltipTextContent,
contentSelector: !tooltipTextContent?.length ? '#tooltip__template' : null,
position: position,
content: textContent,
contentSelector: !textContent?.length ? '#tooltip__template' : null,
contentActions: {
'*': {
eventType: 'click',
Expand All @@ -287,14 +313,16 @@
closeOnCallback: true,
},
},
containerClassName: useCustomTooltipClass ? `tooltip tooltip-${tooltipPosition}` : null,
animated: animateTooltip,
containerClassName: useCustomClass ? `tooltip tooltip-${position}` : null,
animated: animate,
animationEnterClassName: useCustomAnimationEnterClass ? 'tooltip-enter' : null,
animationLeaveClassName: useCustomAnimationLeaveClass ? 'tooltip-leave' : null,
enterDelay: tooltipEnterDelay,
leaveDelay: tooltipLeaveDelay,
offset: tooltipOffset,
disabled: isTooltipDisabled,
enterDelay: enterDelay,
leaveDelay: leaveDelay,
onEnter: _onTooltipEnter,
onLeave: _onTooltipLeave,
offset: offset,
disabled: isDisabled,
}}
class="target"
>
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/svelte": "^3.0.3",
"@untemps/utils": "^2.0.0-beta.1",
"@untemps/utils": "^2.4.0",
"babel-jest": "^28.0.0-alpha.11",
"cross-env": "^7.0.3",
"husky": "^7.0.4",
Expand All @@ -61,6 +61,7 @@
},
"dependencies": {
"@untemps/dom-observer": "^2.0.0",
"@untemps/utils": "^2.4.0",
"svelte": "3.49.0"
},
"jest": {
Expand Down
15 changes: 15 additions & 0 deletions src/Tooltip.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DOMObserver } from '@untemps/dom-observer'
import { standby } from '@untemps/utils/async/standby'

class Tooltip {
static #instances = []
Expand All @@ -16,6 +17,8 @@ class Tooltip {
#animationLeaveClassName = null
#enterDelay = 0
#leaveDelay = 0
#onEnter = null
#onLeave = null
#offset = 10

#observer = null
Expand Down Expand Up @@ -46,6 +49,8 @@ class Tooltip {
animationLeaveClassName,
enterDelay,
leaveDelay,
onEnter,
onLeave,
offset,
disabled
) {
Expand All @@ -60,6 +65,8 @@ class Tooltip {
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
this.#enterDelay = enterDelay || 0
this.#leaveDelay = leaveDelay || 0
this.#onEnter = onEnter || null
this.#onLeave = onLeave || null
this.#offset = Math.max(offset || 10, 5)

this.#observer = new DOMObserver()
Expand All @@ -86,6 +93,8 @@ class Tooltip {
animationLeaveClassName,
enterDelay,
leaveDelay,
onEnter,
onLeave,
offset,
disabled
) {
Expand All @@ -109,6 +118,8 @@ class Tooltip {
this.#animationLeaveClassName = animationLeaveClassName || '__tooltip-leave'
this.#enterDelay = enterDelay || 0
this.#leaveDelay = leaveDelay || 0
this.#onEnter = onEnter || null
this.#onLeave = onLeave || null
this.#offset = Math.max(offset || 10, 5)

if (hasContentChanged || hasPositionChanged || hasOffsetChanged) {
Expand Down Expand Up @@ -366,13 +377,17 @@ class Tooltip {
if (this.#target === e.target) {
await this.#waitForDelay(this.#enterDelay)
await this.#appendTooltipToTarget()
await standby(0)
this.#onEnter?.()
}
}

async #onTargetLeave(e) {
if (this.#target === e.target || !this.#target.contains(e.target)) {
await this.#waitForDelay(this.#leaveDelay)
await this.#removeTooltipFromTarget()
await standby(0)
this.#onLeave?.()
}
}

Expand Down
24 changes: 24 additions & 0 deletions src/__tests__/useTooltip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,30 @@ describe('useTooltip', () => {
})
})

describe('useTooltip props: onEnter', () => {
it('Triggers callback when entering tooltip', async () => {
const onEnter = jest.fn()
action = useTooltip(target, {
...options,
onEnter,
})
await _enter(target)
await standby(0)
expect(onEnter).toHaveBeenCalled()
})

it('Triggers callback when entering tooltip after update', async () => {
const onEnter = jest.fn()
action = useTooltip(target, options)
action.update({
onEnter,
})
await _enter(target)
await standby(0)
expect(onEnter).toHaveBeenCalled()
})
})

describe('useTooltip props: leaveDelay', () => {
it('Delays tooltip disappearance', async () => {
action = useTooltip(target, {
Expand Down
8 changes: 8 additions & 0 deletions src/useTooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const useTooltip = (
animationLeaveClassName,
enterDelay,
leaveDelay,
onEnter,
onLeave,
offset,
disabled,
}
Expand All @@ -31,6 +33,8 @@ const useTooltip = (
animationLeaveClassName,
enterDelay,
leaveDelay,
onEnter,
onLeave,
offset,
disabled
)
Expand All @@ -47,6 +51,8 @@ const useTooltip = (
animationLeaveClassName: newAnimationLeaveClassName,
enterDelay: newEnterDelay,
leaveDelay: newLeaveDelay,
onEnter: newOnEnter,
onLeave: newOnLeave,
offset: newOffset,
disabled: newDisabled,
}) =>
Expand All @@ -61,6 +67,8 @@ const useTooltip = (
newAnimationLeaveClassName,
newEnterDelay,
newLeaveDelay,
newOnEnter,
newOnLeave,
newOffset,
newDisabled
),
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2365,10 +2365,10 @@
resolved "https://registry.yarnpkg.com/@untemps/dom-observer/-/dom-observer-2.0.0.tgz#5b86b091f62905a6f18b0280bbf9067f2949716f"
integrity sha512-oZBj7j9hYSbuveNFvyPLamRfNh15KvGJC5pLGGpWVcO61EzISMESL0wudwP0UZETEu+0WfaJ16rGXtEZHsq+xw==

"@untemps/utils@^2.0.0-beta.1":
version "2.0.0-beta.1"
resolved "https://registry.yarnpkg.com/@untemps/utils/-/utils-2.0.0-beta.1.tgz#c7369b7efb06d0b7283e81e09d42207240dd9f8a"
integrity sha512-XwZzhIRcjDA2em+fGNLjbSqnq8UD5GtqqeENtuQAn73ztcGZCX/5eAhL9BK63wgnalwOO3wN+y9SfN+IXYjt4Q==
"@untemps/utils@^2.4.0":
version "2.4.0"
resolved "https://registry.yarnpkg.com/@untemps/utils/-/utils-2.4.0.tgz#56d47022f289d7c1578d587d33c922d494b921f1"
integrity sha512-SC8iU/J0HLXaDBd1NiXu4Tgal0WaeMIEDP4aaX/aotD8iwLi7vfihGwm970ATHZJphPheuPPZM9igsD4scr9og==
dependencies:
"@babel/runtime" "^7.17.8"

Expand Down