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
4 changes: 2 additions & 2 deletions jest/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import '@testing-library/jest-dom/extend-expect'

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

global._createElement = (id = 'foo', attrs) => {
global._createElement = (id = 'foo', parent, attrs) => {
const el = document.createElement('div')
el.setAttribute('id', id)
for (let key in attrs) {
el.setAttribute(key, attrs[key])
}
document.body.appendChild(el)
;(parent || document.body).appendChild(el)
return el
}

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"@semantic-release/changelog": "^6.0.1",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^8.0.2",
"@testing-library/dom": "^8.11.0",
"@testing-library/dom": "^8.11.3",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/svelte": "^3.0.3",
"babel-jest": "^27.3.1",
Expand Down
55 changes: 42 additions & 13 deletions src/Tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Tooltip {

#boundEnterHandler = null
#boundLeaveHandler = null
#boundKeyDownHandler = null
#boundWindowChangeHandler = null

#target = null
#content = null
Expand Down Expand Up @@ -72,7 +72,7 @@ class Tooltip {
this.#target.setAttribute('style', 'position: relative')
this.#target.setAttribute('aria-describedby', 'tooltip')

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

Tooltip.#instances.push(this)
}
Expand Down Expand Up @@ -122,14 +122,14 @@ class Tooltip {
}

if (hasToDisableTarget) {
this.#disableTarget()
this.#disable()
} else if (hasToEnableTarget) {
this.#enableTarget()
this.#enable()
}
}

destroy() {
this.#removeTooltipFromTarget()
async destroy() {
await this.#removeTooltipFromTarget()

this.#disableTarget()

Expand All @@ -139,28 +139,50 @@ class Tooltip {
this.#observer = null
}

#enable() {
this.#enableTarget()
this.#enableWindow()
}

#enableTarget() {
this.#boundEnterHandler = this.#onTargetEnter.bind(this)
this.#boundLeaveHandler = this.#onTargetLeave.bind(this)
this.#boundKeyDownHandler = this.#onTargetKeyDown.bind(this)

this.#target.addEventListener('mouseenter', this.#boundEnterHandler)
this.#target.addEventListener('mouseleave', this.#boundLeaveHandler)
this.#target.addEventListener('focusin', this.#boundEnterHandler)
this.#target.addEventListener('focusout', this.#boundLeaveHandler)
window.addEventListener('keydown', this.#boundKeyDownHandler)
}

#enableWindow() {
this.#boundWindowChangeHandler = this.#onWindowChange.bind(this)

window.addEventListener('keydown', this.#boundWindowChangeHandler)
window.addEventListener('resize', this.#boundWindowChangeHandler)
window.addEventListener('scroll', this.#boundWindowChangeHandler)
}

#disable() {
this.#disableTarget()
this.#disableWindow()
}

#disableTarget() {
this.#target.removeEventListener('mouseenter', this.#boundEnterHandler)
this.#target.removeEventListener('mouseleave', this.#boundLeaveHandler)
this.#target.removeEventListener('focusin', this.#boundEnterHandler)
this.#target.removeEventListener('focusout', this.#boundLeaveHandler)
window.removeEventListener('keydown', this.#boundKeyDownHandler)

this.#boundEnterHandler = null
this.#boundLeaveHandler = null
this.#boundKeyDownHandler = null
}

#disableWindow() {
window.removeEventListener('keydown', this.#boundWindowChangeHandler)
window.removeEventListener('resize', this.#boundWindowChangeHandler)
window.removeEventListener('scroll', this.#boundWindowChangeHandler)

this.#boundWindowChangeHandler = null
}

#createTooltip() {
Expand Down Expand Up @@ -345,9 +367,16 @@ class Tooltip {
await this.#removeTooltipFromTarget()
}

async #onTargetKeyDown(e) {
if (e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27) {
await this.#onTargetLeave()
async #onWindowChange(e) {
if (
this.#tooltip &&
this.#tooltip.parentNode &&
(e.type !== 'keydown' ||
(e.type === 'keydown' && e.key === 'Escape') ||
e.key === 'Esc' ||
e.keyCode === 27)
) {
await this.#removeTooltipFromTarget()
}
}
}
Expand Down
57 changes: 55 additions & 2 deletions src/__tests__/useTooltip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,27 @@ describe('useTooltip', () => {

const _keyDown = async (key) =>
new Promise(async (resolve) => {
await fireEvent.keyDown(target, key || { key: 'Escape', code: 'Escape', charCode: 27 })
await fireEvent.keyDown(target, key || { key: 'Escape', code: 'Escape', keyCode: 27 })
await _sleep(1)
resolve()
})

const _scroll = async () =>
new Promise(async (resolve) => {
await fireEvent.scroll(window)
await _sleep(1)
resolve()
})

const _resize = async () =>
new Promise(async (resolve) => {
await fireEvent(window, new Event('resize'))
await _sleep(1)
resolve()
})

beforeEach(() => {
target = _createElement('target', { class: 'bar' })
target = _createElement('target', null, { class: 'bar' })
template = _createElement('template')
options = {
contentSelector: '#template',
Expand Down Expand Up @@ -110,9 +124,26 @@ describe('useTooltip', () => {
it('Hides tooltip on escape key down', async () => {
action = useTooltip(target, options)
await _enter()
expect(template).toBeInTheDocument()
await _keyDown()
expect(template).not.toBeInTheDocument()
})

it('Hides tooltip on scroll', async () => {
action = useTooltip(target, options)
await _enter()
expect(template).toBeInTheDocument()
await _scroll()
expect(template).not.toBeInTheDocument()
})

it('Hides tooltip on resize', async () => {
action = useTooltip(target, options)
await _enter()
expect(template).toBeInTheDocument()
await _resize()
expect(template).not.toBeInTheDocument()
})
})

describe('update', () => {
Expand Down Expand Up @@ -213,6 +244,28 @@ describe('useTooltip', () => {
expect(template).toBeInTheDocument()
})

it('Triggers callback on element click within tooltip', async () => {
const newTemplate = _createElement('new-template')
const clickableElement = _createElement('clickable-element', newTemplate)
const contentActions = {
'#clickable-element': {
eventType: 'click',
callback: jest.fn(),
callbackParams: ['foo'],
},
}
action = useTooltip(target, {
...options,
contentSelector: '#new-template',
contentActions,
})
const contentAction = contentActions['#clickable-element']
await _enter()
await fireEvent.click(clickableElement)
expect(contentAction.callback).toHaveBeenCalledWith(contentAction.callbackParams[0], expect.any(Event))
expect(newTemplate).toBeInTheDocument()
})

it('Closes tooltip after triggering callback', async () => {
action = useTooltip(target, options)
options.contentActions['*'].closeOnCallback = true
Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1776,10 +1776,10 @@
lz-string "^1.4.4"
pretty-format "^26.6.2"

"@testing-library/dom@^8.11.0":
version "8.11.0"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.0.tgz#3679dfb4db58e0d2b95e4b0929eaf45237b60d94"
integrity sha512-8Ay4UDiMlB5YWy+ZvCeRyFFofs53ebxrWnOFvCoM1HpMAX4cHyuSrCuIM9l2lVuUWUt+Gr3loz/nCwdrnG6ShQ==
"@testing-library/dom@^8.11.3":
version "8.11.3"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.11.3.tgz#38fd63cbfe14557021e88982d931e33fb7c1a808"
integrity sha512-9LId28I+lx70wUiZjLvi1DB/WT2zGOxUh46glrSNMaWVx849kKAluezVzZrXJfTKKoQTmEOutLes/bHg4Bj3aA==
dependencies:
"@babel/code-frame" "^7.10.4"
"@babel/runtime" "^7.12.5"
Expand Down