mirror of
https://github.com/anomalyco/opencode.git
synced 2026-11-13 19:46:16 +03:00
fix(gui-extensions): keep the Knobs panel open while tuning (#57701)
This commit is contained in:
committed by
GitHub
Unverified
parent
31f2e302db
commit
1744121801
@@ -62,6 +62,33 @@ it("offers Snappy, Smooth and Calm for every spring, with one Global card and on
|
||||
expect(image()).toEqual({ duration: 0.3, bounce: 0 })
|
||||
})
|
||||
|
||||
it("closes only from its own close button or Esc inside it, never from the app around it", async () => {
|
||||
let closed = 0
|
||||
const outside = document.createElement("button")
|
||||
const container = document.createElement("div")
|
||||
document.body.append(outside, container)
|
||||
cleanups.push(mountMotionPanel(container, { onClose: () => closed++ }))
|
||||
|
||||
const close = await waitFor(() => container.querySelector<HTMLButtonElement>(".knobs-close") ?? undefined)
|
||||
|
||||
outside.focus()
|
||||
outside.click()
|
||||
document.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }))
|
||||
document.dispatchEvent(new KeyboardEvent("keydown", { key: "p", metaKey: true, bubbles: true }))
|
||||
expect(closed).toBe(0)
|
||||
|
||||
const random = await waitFor(
|
||||
() => container.querySelector<HTMLButtonElement>('button[aria-label="Random"]') ?? undefined,
|
||||
)
|
||||
|
||||
random.focus()
|
||||
random.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true, cancelable: true }))
|
||||
expect(closed).toBe(1)
|
||||
|
||||
close.click()
|
||||
expect(closed).toBe(2)
|
||||
})
|
||||
|
||||
async function waitFor<T>(find: () => T | undefined) {
|
||||
for (let i = 0; i < 200; i++) {
|
||||
const found = find()
|
||||
|
||||
@@ -34,9 +34,9 @@ export default {
|
||||
"mem.label": "MEM",
|
||||
"mem.tipUnavailable": "Used JS heap vs heap limit. Chromium only.",
|
||||
"mem.tip": "Used JS heap vs heap limit. {{used}} of {{limit}}.",
|
||||
"motion.label": "MOTION",
|
||||
"motion.title": "Motion",
|
||||
"motion.tip": "Tune animation springs live. Changes persist on this device.",
|
||||
"motion.label": "KNOBS",
|
||||
"motion.title": "Knobs",
|
||||
"motion.tip": "Tune live. Changes persist on this device.",
|
||||
"speed.label": "SPEED",
|
||||
"speed.tip": "Global animation speed. Click to step through 0.5× and 0.25× back to 1×.",
|
||||
"slow.label": "SLOW",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Portal } from "solid-js/web"
|
||||
const key = "opencode.motion.panel"
|
||||
|
||||
// The Motion workspace, docked above the debug bar's right end until its header is dragged. knobs loads once it opens.
|
||||
export default function Motion(props: { title: string }) {
|
||||
export default function Motion(props: { title: string; onClose: () => void }) {
|
||||
let container!: HTMLDivElement
|
||||
let unmount: (() => void) | undefined
|
||||
let disposed = false
|
||||
@@ -76,7 +76,7 @@ export default function Motion(props: { title: string }) {
|
||||
})
|
||||
|
||||
void import("@opencode/ui/motion-tuning-panel").then(({ mountMotionPanel }) => {
|
||||
if (!disposed) unmount = mountMotionPanel(container, { title: props.title })
|
||||
if (!disposed) unmount = mountMotionPanel(container, { title: props.title, onClose: props.onClose })
|
||||
})
|
||||
|
||||
return (
|
||||
|
||||
@@ -50,10 +50,10 @@ const setup: Setup<typeof Debug> = (ctx) => {
|
||||
</Suspense>
|
||||
</Show>
|
||||
{Motion && (
|
||||
// The Motion workspace opens only from the debug bar's MOTION cell, and shows while the bar does.
|
||||
// The Knobs workspace opens only from the debug bar's KNOBS cell, and shows while the bar does.
|
||||
<Show when={visible() && motion()}>
|
||||
<Suspense>
|
||||
<Motion title={ctx.t("motion.title")} />
|
||||
<Motion title={ctx.t("motion.title")} onClose={toggleMotion} />
|
||||
</Suspense>
|
||||
</Show>
|
||||
)}
|
||||
|
||||
@@ -10,7 +10,10 @@ const global = "Global"
|
||||
* mount, so importing this module costs nothing until then. Works anywhere a surface registered its knobs, including
|
||||
* Storybook stories. Returns its removal.
|
||||
*/
|
||||
export function mountMotionPanel(container: HTMLElement, options: { title?: string; section?: string } = {}) {
|
||||
export function mountMotionPanel(
|
||||
container: HTMLElement,
|
||||
options: { title?: string; section?: string; onClose?: () => void } = {},
|
||||
) {
|
||||
let unmount: (() => void) | undefined
|
||||
let disposed = false
|
||||
let section = options.section
|
||||
@@ -113,7 +116,8 @@ export function mountMotionPanel(container: HTMLElement, options: { title?: stri
|
||||
|
||||
const stopPanel = controls.mount(container, {
|
||||
theme: "auto",
|
||||
title: options.title ?? "Motion",
|
||||
title: options.title ?? "Knobs",
|
||||
onClose: options.onClose,
|
||||
tabs: sections,
|
||||
tab: section,
|
||||
onTab: (id) => (section = id),
|
||||
|
||||
Reference in New Issue
Block a user