js-hoverintent
Version:
Hover intent in javascript
99 lines (84 loc) • 2.42 kB
JavaScript
const debounce = (callback, wait) => {
let timeout
const cancel = () => {
clearTimeout(timeout)
}
const debounced = (...args) => {
cancel()
timeout = setTimeout(callback, +wait, ...args)
}
debounced.cancel = cancel
return debounced
}
const intent = (
startDebounceEvent,
cancelDebounceEvent,
elements,
callback,
wait
) => {
if (typeof callback !== 'function') {
throw new TypeError('Expected a function')
}
const debouncer = debounce(callback, +wait)
/**
* Add startDebounceEvent listener to the given element via debouncer callback.
*
* @param {HTMLElement} elm A dom element.
*
* @returns {Function} A function to remove debouncer callback from startDebounceEvent listener.
*/
const startDebouncer = elm => {
elm.addEventListener(startDebounceEvent, debouncer)
return () => elm.removeEventListener(startDebounceEvent, debouncer)
}
/**
* Add cancelDebounceEvent listener to the given element via debouncer.cancel callback.
*
* @param {HTMLElement} elm A dom element.
*
* @returns {Function} A function to remove debouncer.cancel callback from cancelDebounceEvent listener.
*/
const cancelDebouncer = elm => {
elm.addEventListener(cancelDebounceEvent, debouncer.cancel)
return () => elm.removeEventListener(cancelDebounceEvent, debouncer.cancel)
}
const removeEventListener = []
elements.forEach(elm => {
removeEventListener.push([startDebouncer(elm), cancelDebouncer(elm)])
})
const cancel = () => {
removeEventListener.forEach(([removeStart, removeCancel]) => {
removeStart()
removeCancel()
})
debouncer.cancel()
}
return cancel
}
const enter = (...args) => intent('mouseenter', 'mouseleave', ...args)
const leave = (...args) => intent('mouseleave', 'mouseenter', ...args)
export default class HoverIntent {
constructor(selector, enterCallback, leaveCallback, options) {
const defaultOptions = {
enterWait: 100,
leaveWait: 100
}
this.selector = document.querySelectorAll(selector)
this.options = Object.assign({}, defaultOptions, options)
this.cancelEnter = enter(
this.selector,
enterCallback,
this.options.enterWait
)
this.cancelLeave = leave(
this.selector,
leaveCallback,
this.options.leaveWait
)
}
cancel() {
this.cancelEnter()
this.cancelLeave()
}
}