uttrflow / uttrflow/uttrflow-swift
[P2] Cancelling a clipboard sheet hides the whole panel before its redraw
- Dominant language
- Swift
- Stars
- 4
- Forks
- 17
- Avg merge
- 4h 27m
- Merged PRs (30d)
- 286
Description
Cancel in a clipboard sheet closes the entire panel, although the domain action correctly cancels only the sheet. The same happens when pressing Escape in its text field or clicking the dimmed background. This interrupts browsing and leaves the app holding an open panel snapshot behind a hidden window.
### Path on main
Reviewed `5c310667cd35c44abd8bbd26c19b0905471287b4`:
- `Sources/Uttrflow/Panel/QuickPanelView.swift`: the sheet Cancel button, background click and sheet-field Escape all call `relayKey(.escape)`. With no row menu open, this forwards Escape to the controller.
- `Sources/Uttrflow/Panel/QuickPanelController.swift`, `relay`: immediately calls `hide()` for every Escape, then calls `onKey`.
- `Sources/UttrflowUX/PanelKeyboard.swift:106`: with a sheet open, Escape produces `closingSheet()` and `.open`, whose effect is `.redraw`.
- `Sources/Uttrflow/AppDelegate.swift:831`: the redraw branch calls `quickPanel.update(...)`. That replaces the view but never orders the window back on screen. `closeQuickPanel()` is not called, so this also bypasses the normal snapshot/resume cleanup.
### Reproduction
Open the clipboard panel, choose Name for a clip, then click Cancel or press Escape in the name field. Expected: the sheet disappears and the clip list remains visible. Actual code path: the window is hidden before the sheet cancellation is applied.
### Verification
A focused test compiled the unmodified QuickPanelController and used a real NSPanel positioned offscreen. Its hosted content was a lightweight placeholder carrying the controller callbacks, not the production SwiftUI sheet. The test started with a real PanelSnapshot alias sheet, verified the native panel was visible, and invoked the hosted Escape callback. Its callback applied the production state transition and the same `controller.update` operation used by AppDelegate's redraw branch:
```
After Cancel relay: sheetNil=true, nativePanelVisible=false
```
The assertion that the panel remains visible fails. This verifies the controller/window/state integration; no physical keypress or click was synthesized. The production sheet-to-Escape route was verified by source inspection.
### Expected fix
Let the resolved panel outcome decide whether the window closes. Preserve immediate close behavior for Escape with no sheet and menu-only dismissal for Escape with a row menu open. Add a controller-level regression proving sheet cancellation keeps the panel visible and normal dismissal still performs snapshot cleanup.
Related #630 tracks extracting/testing view keyboard mapping while preserving behavior. This is a concrete controller visibility defect requiring a behavior fix, rather than another request for that extraction.
Contributor guide
Research direction
Start in Sources/Uttrflow/Panel/QuickPanelController.swift at relay and trace the Escape path into Sources/Uttrflow/AppDelegate.swift:831 and PanelKeyboard.swift:106. Reproduce clipboard-sheet cancellation, then add the controller-level regression described in the issue. Done means sheet cancellation redraws while the native panel remains visible, while normal dismissal still performs snapshot cleanup.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, swift
- Domain
- desktop, testing
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100