Files
openclaw/ui/src/components/github-link-hovercard-registration.ts
T
Peter Steinberger cef071582e feat: let limited browsers request admin access (#121459)
* feat(gateway): add live device scope upgrades

* feat(ui): add limited-access upgrade flow

* fix(protocol): refresh Swift scope upgrade models

* perf(ui): lazy-load device scope upgrades

* fix(ci): complete scope upgrade generated surfaces

* perf(ui): lazy-load GitHub link hovercards

* fix(ui): keep admin repair guidance focusable

* fix(ui): gate and refresh scope upgrade banner

* refactor(ui): keep gateway client within line budget

* fix(ci): align rebased scope upgrade checks

* fix(ui): resolve scope upgrade in browser tests

* fix(gateway): honor refreshed scope upgrade deadline

* fix(gateway): honor refreshed scope upgrade deadline

* fix(gateway): coalesce scope upgrade waiters

* fix(ui): gate scope upgrade actions

* chore(plugin-sdk): refresh rebased API baseline

* fix(scope-upgrade): return canonical request ids

* fix(ui): preserve gateway event type binding

* fix(protocol): generate scope upgrade result models

* fix(ui): preserve scope upgrade recovery guidance

* chore(plugin-sdk): refresh rebased API baseline

* test(ui): avoid scope upgrade navigation race

* docs(control-ui): clarify scope upgrade approver

* test(gateway): align appended method counts

* chore(plugin-sdk): refresh rebased API baseline

* refactor(ui): keep place picker within line budget

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* chore(plugin-sdk): refresh rebased API baseline

* fix(gateway): preserve scope-upgrade browser origin
2026-08-12 18:32:00 -07:00

76 lines
2.6 KiB
TypeScript

import type { GatewayBrowserClient } from "../api/gateway.ts";
import { ensureCustomElementDefined } from "../app/lazy-custom-element.ts";
import type { GitHubLinkHovercardProvider } from "./github-link-hovercard.runtime.ts";
import {
GITHUB_HOVERCARD_OPEN_DELAY_MS,
githubLinkAnchorFromEvent,
parseGitHubLinkTarget,
} from "./github-link-target.ts";
const HOVERCARD_TAG = "openclaw-github-link-hovercard-provider";
type HovercardProviderElement = HTMLElement & {
client: GatewayBrowserClient | null;
};
function providerForAnchor(anchor: HTMLAnchorElement): GitHubLinkHovercardProvider | null {
return anchor.closest<GitHubLinkHovercardProvider>(HOVERCARD_TAG);
}
function removeBootstrapListeners(): void {
document.removeEventListener("pointerover", handleBootstrapPointerOver, true);
document.removeEventListener("focusin", handleBootstrapFocusIn, true);
}
async function activateHovercard(event: Event, trigger: "focus" | "pointer"): Promise<void> {
if (trigger === "pointer" && (event as PointerEvent).pointerType === "touch") {
return;
}
const anchor = githubLinkAnchorFromEvent(event);
const target = anchor ? parseGitHubLinkTarget(anchor.href) : null;
if (!anchor || !target || !providerForAnchor(anchor)) {
return;
}
const startedAt = performance.now();
const pendingClients = new Map(
[...document.querySelectorAll<HovercardProviderElement>(HOVERCARD_TAG)].map((provider) => [
provider,
provider.client,
]),
);
await ensureCustomElementDefined(HOVERCARD_TAG, async () => {
const runtime = await import("./github-link-hovercard.runtime.ts");
customElements.define(HOVERCARD_TAG, runtime.GitHubLinkHovercardProvider);
for (const [provider, client] of pendingClients) {
provider.client = client;
}
});
removeBootstrapListeners();
const provider = providerForAnchor(anchor);
const stillActive =
trigger === "pointer" ? anchor.matches(":hover") : document.activeElement === anchor;
if (!provider || !anchor.isConnected || !stillActive) {
return;
}
const delay =
trigger === "pointer"
? Math.max(0, GITHUB_HOVERCARD_OPEN_DELAY_MS - (performance.now() - startedAt))
: 0;
provider.activateFromBootstrap(anchor, target, trigger, delay);
}
function handleBootstrapPointerOver(event: Event): void {
void activateHovercard(event, "pointer");
}
function handleBootstrapFocusIn(event: Event): void {
void activateHovercard(event, "focus");
}
if (customElements.get(HOVERCARD_TAG)) {
removeBootstrapListeners();
} else {
document.addEventListener("pointerover", handleBootstrapPointerOver, true);
document.addEventListener("focusin", handleBootstrapFocusIn, true);
}