Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allowing any key (or a specified set of keys) to trigger keyboard navigation mode, allowing to specify a set of dissmiss keyboard navigation mode keys. #27

Merged
merged 1 commit into from
Jan 12, 2023
Merged
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
56 changes: 41 additions & 15 deletions src/Keyborg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,20 @@ interface WindowWithKeyborg extends Window {
};
}

const KeyTab = 9;
const KeyEsc = 27;

const _dismissTimeout = 500; // When Esc is pressed and the focused is not moved
// during _dismissTimeout time, dismiss the keyboard
// navigation mode.
const _dismissTimeout = 500; // When a key from dismissKeys is pressed and the focus is not moved
// during _dismissTimeout time, dismiss the keyboard navigation mode.

let _lastId = 0;

export interface KeyborgProps {
// Keys to be used to trigger keyboard navigation mode. By default, any key will trigger
// it. Could be limited to, for example, just Tab (or Tab and arrow keys).
triggerKeys?: number[];
// Keys to be used to dismiss keyboard navigation mode using keyboard (in addition to
// mouse clicks which dismiss it). For example, Esc could be used to dismiss.
dismissKeys?: number[];
}

export type KeyborgCallback = (isNavigatingWithKeyboard: boolean) => void;

/**
Expand Down Expand Up @@ -88,12 +93,27 @@ class KeyborgCore implements Disposable {
private _win?: WindowWithKeyborg;
private _isMouseUsed = false;
private _dismissTimer: number | undefined;
private _triggerKeys?: Set<number>;
private _dismissKeys?: Set<number>;

constructor(win: WindowWithKeyborg) {
constructor(win: WindowWithKeyborg, props?: KeyborgProps) {
this.id = "c" + ++_lastId;
this._win = win;
const doc = win.document;

if (props) {
const triggerKeys = props.triggerKeys;
mshoho marked this conversation as resolved.
Show resolved Hide resolved
const dismissKeys = props.dismissKeys;

if (triggerKeys?.length) {
this._triggerKeys = new Set(triggerKeys);
}

if (dismissKeys?.length) {
this._dismissKeys = new Set(dismissKeys);
}
}

doc.addEventListener(KEYBORG_FOCUSIN, this._onFocusIn, true); // Capture!
doc.addEventListener("mousedown", this._onMouseDown, true); // Capture!
win.addEventListener("keydown", this._onKeyDown, true); // Capture!
Expand Down Expand Up @@ -190,9 +210,15 @@ class KeyborgCore implements Disposable {
private _onKeyDown = (e: KeyboardEvent): void => {
const isNavigatingWithKeyboard = _state.getVal();

if (!isNavigatingWithKeyboard && e.keyCode === KeyTab) {
const keyCode = e.keyCode;
const triggerKeys = this._triggerKeys;

if (
!isNavigatingWithKeyboard &&
(!triggerKeys || triggerKeys.has(keyCode))
) {
_state.setVal(true);
} else if (isNavigatingWithKeyboard && e.keyCode === KeyEsc) {
} else if (isNavigatingWithKeyboard && this._dismissKeys?.has(keyCode)) {
this._scheduleDismiss();
}
};
Expand Down Expand Up @@ -232,8 +258,8 @@ export class Keyborg {
private _core?: KeyborgCore;
private _cb: KeyborgCallback[] = [];

static create(win: WindowWithKeyborg): Keyborg {
return new Keyborg(win);
static create(win: WindowWithKeyborg, props?: KeyborgProps): Keyborg {
mshoho marked this conversation as resolved.
Show resolved Hide resolved
return new Keyborg(win, props);
}

static dispose(instance: Keyborg): void {
Expand All @@ -247,7 +273,7 @@ export class Keyborg {
instance._cb.forEach((callback) => callback(isNavigatingWithKeyboard));
}

private constructor(win: WindowWithKeyborg) {
private constructor(win: WindowWithKeyborg, props?: KeyborgProps) {
mshoho marked this conversation as resolved.
Show resolved Hide resolved
this._id = "k" + ++_lastId;
this._win = win;

Expand All @@ -257,7 +283,7 @@ export class Keyborg {
this._core = current.core;
current.refs[this._id] = this;
} else {
this._core = new KeyborgCore(win);
this._core = new KeyborgCore(win, props);
win.__keyborg = {
core: this._core,
refs: { [this._id]: this },
Expand Down Expand Up @@ -320,8 +346,8 @@ export class Keyborg {
}
}

export function createKeyborg(win: Window): Keyborg {
return Keyborg.create(win);
export function createKeyborg(win: Window, props?: KeyborgProps): Keyborg {
mshoho marked this conversation as resolved.
Show resolved Hide resolved
return Keyborg.create(win, props);
}

export function disposeKeyborg(instance: Keyborg) {
Expand Down