bits-ui
Version:
The headless components for Svelte.
52 lines (51 loc) • 1.89 kB
JavaScript
import { executeCallbacks } from "svelte-toolbelt";
import { on } from "svelte/events";
// Using global state to avoid multiple listeners.
let isUsingKeyboard = $state(false);
/**
* Detects whether the user is currently using the keyboard
* or not by listening to keyboard and pointer events. Uses shared global
* state to avoid listener duplication.
*/
export class IsUsingKeyboard {
static _refs = 0; // Reference counting to avoid multiple listeners.
static _cleanup;
constructor() {
$effect(() => {
if (IsUsingKeyboard._refs === 0) {
IsUsingKeyboard._cleanup = $effect.root(() => {
const callbacksToDispose = [];
const handlePointer = (_) => {
isUsingKeyboard = false;
};
const handleKeydown = (_) => {
isUsingKeyboard = true;
};
callbacksToDispose.push(on(document, "pointerdown", handlePointer, {
capture: true,
}), on(document, "pointermove", handlePointer, {
capture: true,
}), on(document, "keydown", handleKeydown, {
capture: true,
}));
// Don't forget to spread and call twice.
return executeCallbacks(...callbacksToDispose);
});
}
IsUsingKeyboard._refs++;
return () => {
IsUsingKeyboard._refs--;
if (IsUsingKeyboard._refs === 0) {
isUsingKeyboard = false;
IsUsingKeyboard._cleanup?.();
}
};
});
}
get current() {
return isUsingKeyboard;
}
set current(value) {
isUsingKeyboard = value;
}
}