-
-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
152 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { readable } from 'svelte/store'; | ||
import { addEventListener } from './helpers/event.js'; | ||
import { chain } from './prevent-scroll.js'; | ||
import { isFunction, isHTMLElement, noop } from '$lib/internal/helpers/index.js'; | ||
|
||
/** | ||
* Creates a readable store that tracks the latest Escape Keydown that occurred on the document. | ||
* | ||
* @returns A function to unsubscribe from the event listener and stop tracking keydown events. | ||
*/ | ||
const documentEscapeKeyStore = readable<KeyboardEvent | undefined>( | ||
undefined, | ||
(set): (() => void) => { | ||
/** | ||
* Event handler for keydown events on the document. | ||
* Updates the store's value with the latest Escape Keydown event and then resets it to undefined. | ||
*/ | ||
function keydown(event: KeyboardEvent | undefined) { | ||
if (event && event.key === 'Escape') { | ||
set(event); | ||
} | ||
|
||
// New subscriptions will not trigger immediately | ||
set(undefined); | ||
} | ||
|
||
// Adds a keydown event listener to the document, calling the keydown function when triggered. | ||
const unsubscribe = addEventListener(document, 'keydown', keydown, { | ||
passive: false | ||
}); | ||
|
||
// Returns a function to unsubscribe from the event listener and stop tracking keydown events. | ||
return unsubscribe; | ||
} | ||
); | ||
|
||
export const useEscapeKeydown = (node: HTMLElement, config: EscapeKeydownConfig = {}) => { | ||
let unsub = noop; | ||
function update(config: EscapeKeydownConfig = {}) { | ||
unsub(); | ||
|
||
unsub = chain( | ||
// Handle escape keydowns | ||
documentEscapeKeyStore.subscribe((e) => { | ||
if (!e) return; | ||
const target = e.target; | ||
|
||
if (!isHTMLElement(target) || target.closest('[data-escapee]') !== node) { | ||
return; | ||
} | ||
|
||
e.preventDefault(); | ||
|
||
// If an ignore function is passed, check if it returns true | ||
if (config.ignore) { | ||
if (isFunction(config.ignore)) { | ||
if (config.ignore(e)) return; | ||
} | ||
// If an ignore array is passed, check if any elements in the array match the target | ||
else if (Array.isArray(config.ignore)) { | ||
if ( | ||
config.ignore.length > 0 && | ||
config.ignore.some((ignoreEl) => { | ||
return ignoreEl && target === ignoreEl; | ||
}) | ||
) | ||
return; | ||
} | ||
} | ||
|
||
// If none of the above conditions are met, call the handler | ||
config.handler?.(e); | ||
}), | ||
(node.dataset.escapee = '') | ||
); | ||
} | ||
|
||
update(config); | ||
|
||
return { | ||
update, | ||
destroy() { | ||
node.removeAttribute('data-escapee'); | ||
unsub(); | ||
} | ||
}; | ||
}; | ||
|
||
export type EscapeKeydownConfig = { | ||
/** | ||
* Callback when user presses the escape key element. | ||
*/ | ||
handler?: (evt: KeyboardEvent) => void; | ||
|
||
/** | ||
* A predicate function or a list of elements that should not trigger the event. | ||
*/ | ||
ignore?: ((e: KeyboardEvent) => boolean) | Element[]; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
export * from './store.js'; | ||
export * from './object.js'; | ||
export * from './style.js'; | ||
export * from './noop.js'; | ||
export * from './event.js'; | ||
export * from './is.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export function isHTMLElement(el: unknown): el is HTMLElement { | ||
return el instanceof HTMLElement; | ||
} | ||
|
||
export const isBrowser = typeof document !== 'undefined'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/ban-types | ||
export function isFunction(v: unknown): v is Function { | ||
return typeof v === 'function'; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export function noop() { | ||
// do nothing; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters