import { useNavigate, useRouterState } from "@tanstack/react-router"; import { useEffect } from "react"; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null; } const REF_ROUTES = new Set(["/$owner/$repo/tree/$", "/$owner/$repo/blob/$", "/$owner/$repo/commits/$"]); const EDIT_ROUTE = "/$owner/$repo/edit/$"; function loaderRef(data: unknown): string | null { if (!isRecord(data)) return null; const ref = data.ref; if (typeof ref === "string") return ref; return isRecord(ref) && typeof ref.name === "string" ? ref.name : null; } function loaderPath(data: unknown): string | null { return isRecord(data) && typeof data.path === "string" && data.path ? data.path : null; } function isTyping(target: EventTarget | null): boolean { if (!(target instanceof HTMLElement)) return false; return target.isContentEditable || ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName); } /** Pressing `.` anywhere in a repository opens the workspace editor on the ref being viewed, like github.dev. */ export function useEditorHotkey(owner: string, repo: string, defaultBranch: string, enabled = true) { const navigate = useNavigate(); const matches = useRouterState({ select: (state) => state.matches }); const editing = matches.some((match) => match.routeId === EDIT_ROUTE); const path = matches .filter((match) => match.routeId === "/$owner/$repo/blob/$") .map((match) => loaderPath(match.loaderData)) .findLast((value) => value !== null) ?? null; const ref = matches .filter((match) => REF_ROUTES.has(match.routeId)) .map((match) => loaderRef(match.loaderData)) .findLast((value) => value !== null) ?? defaultBranch; useEffect(() => { if (editing || !enabled) return; function onKey(event: KeyboardEvent) { if (event.key !== "." || event.metaKey || event.ctrlKey || event.altKey || isTyping(event.target)) return; event.preventDefault(); void navigate({ to: "/$owner/$repo/edit/$", params: { owner, repo, _splat: ref }, search: path ? { path } : {} }); } window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [navigate, owner, repo, ref, path, editing, enabled]); }