mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-15 04:27:20 +03:00
fix(site): let OpenCode Lite take the keys after DevTools opens mid-load (#62301)
This commit is contained in:
@@ -104,9 +104,19 @@ export function install() {
|
||||
// One OpenCode Lite at a time. Quitting it brings the greeting back, and stops it from starting on
|
||||
// its own in this browser (people who debug the site open DevTools all day) until opencode.try().
|
||||
let lite: Promise<{ stop: () => void }> | undefined
|
||||
const startLite = () => {
|
||||
lite ??= textjs<{ start: (options: { onExit: () => void }) => Promise<{ stop: () => void }> }>("lite").then((app) =>
|
||||
const startLite = (reason?: string) => {
|
||||
if (lite) return lite
|
||||
// Lite takes a moment to download, and the visitor may click back into the page from DevTools
|
||||
// meanwhile. Its keyboard needs to know that focus left the page (see src/lite.tsx). A DevTools
|
||||
// shortcut counts at once, since DevTools takes focus as it opens.
|
||||
let away = reason === "shortcut" || !document.hasFocus()
|
||||
const blur = () => (away = true)
|
||||
window.addEventListener("blur", blur)
|
||||
lite = textjs<{
|
||||
start: (options: { away: () => boolean; onExit: () => void }) => Promise<{ stop: () => void }>
|
||||
}>("lite").then((app) =>
|
||||
app.start({
|
||||
away: () => away,
|
||||
onExit: () => {
|
||||
lite = undefined
|
||||
localStorage.setItem(liteQuitKey, "1")
|
||||
@@ -121,7 +131,7 @@ export function install() {
|
||||
},
|
||||
}),
|
||||
)
|
||||
lite.catch(() => (lite = undefined))
|
||||
lite.finally(() => window.removeEventListener("blur", blur)).catch(() => (lite = undefined))
|
||||
return lite
|
||||
}
|
||||
|
||||
@@ -287,10 +297,10 @@ export function install() {
|
||||
// Settings › Other › Console API removes window.opencode when it's turned off, and Lite may have
|
||||
// been started by hand and quit since this page loaded.
|
||||
const intent = textjs.onConsoleIntent(
|
||||
() =>
|
||||
(e) =>
|
||||
(window as { opencode?: unknown }).opencode === api &&
|
||||
!localStorage.getItem(liteQuitKey) &&
|
||||
void startLite().catch(greetOnce),
|
||||
void startLite(e.reason).catch(greetOnce),
|
||||
{ engageSelector: false },
|
||||
)
|
||||
if (!intent.triggered) greetOnce()
|
||||
|
||||
@@ -14,14 +14,26 @@ import { createDemoClient } from "../.upstream/opencode-console/lib/demo"
|
||||
// `new URL("@textjs/core/yoga.wasm", import.meta.url)`, so load it from next to the chunks.
|
||||
declare const __TEXTJS_YOGA__: string
|
||||
|
||||
export async function start(options: { onExit?: () => void } = {}) {
|
||||
export async function start(options: { away?: () => boolean; onExit?: () => void } = {}) {
|
||||
await initYoga({ wasm: new URL(__TEXTJS_YOGA__, import.meta.url) })
|
||||
// Text.js 1.6 counts a press as the click back from DevTools only within 300 ms of the window's
|
||||
// focus event, so it misses a visitor who came back while Lite loaded: their clicks on the page,
|
||||
// which already has focus, never reached Lite. Replay that focus for their next press, until
|
||||
// Text.js ships createHostInput({ away }), which does this itself. Registered first, so it runs
|
||||
// before createHostInput's own listener.
|
||||
const replay = (e: MouseEvent) => {
|
||||
if (e.button !== 0 || e.ctrlKey) return
|
||||
document.removeEventListener("mousedown", replay, true)
|
||||
window.dispatchEvent(new FocusEvent("focus"))
|
||||
}
|
||||
if (options.away?.() && document.hasFocus()) document.addEventListener("mousedown", replay, true)
|
||||
// Keys reach the app only once the visitor clicks the page to come back from DevTools, and never
|
||||
// while they type in one of its fields, so the site's own shortcuts keep working until then.
|
||||
const input = createHostInput()
|
||||
const stop = () => {
|
||||
root.unmount()
|
||||
input.dispose()
|
||||
document.removeEventListener("mousedown", replay, true)
|
||||
}
|
||||
const exit = () => {
|
||||
stop()
|
||||
|
||||
Reference in New Issue
Block a user