2023-03-05 08:17:02 -08:00
|
|
|
import { Controller } from "@hotwired/stimulus";
|
|
|
|
import { install, uninstall } from "@github/hotkey";
|
|
|
|
|
|
|
|
export default class extends Controller {
|
|
|
|
static classes = ["current"];
|
|
|
|
static targets = ["current", "traversable"];
|
|
|
|
|
|
|
|
declare readonly hasCurrentTarget: boolean;
|
|
|
|
declare readonly currentTarget: HTMLElement;
|
|
|
|
declare readonly traversableTargets: HTMLElement[];
|
|
|
|
|
2023-03-05 10:38:31 -08:00
|
|
|
traversableTargetConnected(target: HTMLElement): void {
|
2023-03-05 10:20:08 -08:00
|
|
|
if (!("navigationIndex" in target.dataset)) {
|
|
|
|
target.dataset.navigationIndex = this.traversableTargets.indexOf(target).toString();
|
|
|
|
}
|
|
|
|
|
2023-03-05 08:17:02 -08:00
|
|
|
if (!this.hasCurrentTarget) {
|
|
|
|
const first = this.traversableTargets[0];
|
2023-03-05 10:20:08 -08:00
|
|
|
first.dataset.navigationTarget += " current";
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-05 10:38:31 -08:00
|
|
|
currentTargetConnected(target: HTMLElement): void {
|
2023-03-05 10:20:08 -08:00
|
|
|
target.classList.add("js-hotkey-current-selection");
|
|
|
|
|
2023-03-05 08:17:02 -08:00
|
|
|
target.querySelectorAll<HTMLElement>("[data-selection-hotkey]")
|
2023-03-05 10:20:08 -08:00
|
|
|
.forEach(el => install(el, el.dataset.selectionHotkey));
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
|
2023-03-05 10:38:31 -08:00
|
|
|
currentTargetDisconnected(target: HTMLElement): void {
|
2023-03-05 10:20:08 -08:00
|
|
|
target.classList.remove("js-hotkey-current-selection");
|
|
|
|
|
2023-03-05 08:17:02 -08:00
|
|
|
target.querySelectorAll<HTMLElement>("[data-selection-hotkey]")
|
2023-03-05 10:20:08 -08:00
|
|
|
.forEach(el => uninstall(el));
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
up(): void {
|
2023-03-05 10:20:08 -08:00
|
|
|
const prevIndex = this.traversableTargets.indexOf(this.currentTarget) - 1;
|
|
|
|
if (prevIndex == -1) return;
|
|
|
|
|
|
|
|
this.navigate(this.traversableTargets[prevIndex]);
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
down(): void {
|
2023-03-05 10:20:08 -08:00
|
|
|
const nextIndex = this.traversableTargets.indexOf(this.currentTarget) + 1;
|
|
|
|
if (nextIndex == this.traversableTargets.length) return;
|
|
|
|
|
|
|
|
this.navigate(this.traversableTargets[nextIndex]);
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
navigate(target: HTMLElement): void {
|
|
|
|
if (!document.body.classList.contains("js-hotkey-navigating")) {
|
|
|
|
document.body.classList.add("js-hotkey-navigating");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target.dataset.navigationTarget == "traversable") {
|
|
|
|
this.currentTarget.dataset.navigationTarget = "traversable";
|
2023-03-05 10:20:08 -08:00
|
|
|
target.dataset.navigationTarget = "traversable current";
|
2023-03-05 10:23:42 -08:00
|
|
|
target.scrollIntoView({ block: "center", inline: "center" });
|
2023-03-05 08:17:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|