WIP: clear search before closing shelf

This commit is contained in:
Akshay Kolli
2026-06-30 09:44:45 -07:00
parent 83e347d507
commit d64665bd98
4 changed files with 66 additions and 6 deletions

View File

@@ -42,7 +42,7 @@ Use this checklist before a release or after changes to panel, pasteboard, setti
9. With a card or collection chip focused, type a normal character and confirm focus returns to search with that character inserted and results filtered.
10. Use a mouse wheel or two-finger vertical scroll over the card shelf and a crowded collection rail; confirm each pans horizontally, clamps at both ends, and shows subtle edge fades only where more content is hidden.
11. Right-click a filtered result and choose Show in Clipboard, or press `Command + G`, and confirm search clears while the same card stays selected in Most Recent.
12. Press `Esc` once with a non-empty search field and confirm search clears.
12. Press `Esc` once with a non-empty search while the search field, a card, or a collection chip is focused and confirm search clears without closing the panel.
13. Press `Esc` again and confirm the panel closes.
14. Reopen the panel, change sort segments, and confirm each segment updates results.
15. Press `Shift + Command + N` or the collection rail `+`, enter `Client Work`, choose a color, and confirm a Client Work chip appears with 0 clips and an empty collection view.

View File

@@ -390,7 +390,9 @@ final class ClipboardPanelController: NSObject, NSWindowDelegate, QLPreviewPanel
}
switch event.keyCode {
case 53:
self.hide()
if !self.panelView.clearSearchForKeyboardCancel() {
self.hide()
}
return nil
case 49:
self.previewSelected()

View File

@@ -1231,6 +1231,15 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
window?.makeFirstResponder(searchField)
}
@discardableResult
func clearSearchForKeyboardCancel() -> Bool {
guard !searchField.stringValue.clipboardTrimmed.isEmpty else { return false }
searchField.stringValue = ""
updateSearchText()
focusSearchField()
return true
}
private func startSearchFromShelf(_ text: String) {
guard !text.isEmpty else { return }
focusSearchField()
@@ -1495,6 +1504,11 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
debugPressFocusedResponder(characters: characters, keyCode: keyCode)
}
func debugSetSearchFieldText(_ text: String) {
searchField.stringValue = text
updateSearchText()
}
private func debugPressFocusedResponder(characters: String, keyCode: UInt16) {
guard let window,
let event = NSEvent.keyEvent(
@@ -1635,11 +1649,10 @@ final class ClipboardPanelView: NSVisualEffectView, NSSearchFieldDelegate {
viewModel.pasteSelected()
return true
case #selector(NSResponder.cancelOperation(_:)):
if searchField.stringValue.clipboardTrimmed.isEmpty {
onClose()
if clearSearchForKeyboardCancel() {
return true
} else {
searchField.stringValue = ""
updateSearchText()
onClose()
}
return true
case #selector(NSResponder.moveUp(_:)):

View File

@@ -263,6 +263,28 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum reference"])
}
func testKeyboardCancelClearsSearchFromFocusedCollectionChip() {
let fixture = makePanelFixture()
fixture.store.upsert(makeTextItem("Alpha note", store: fixture.store))
fixture.store.upsert(makeTextItem("Quantum reference", store: fixture.store))
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
fixture.view.debugSetSearchFieldText("quantum")
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum reference"])
XCTAssertTrue(fixture.view.debugFocusCollectionChip(.text))
XCTAssertTrue(fixture.view.clearSearchForKeyboardCancel())
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertTrue(fixture.view.isSearchFieldEditing)
XCTAssertEqual(fixture.view.debugSearchFieldText, "")
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum reference", "Alpha note"])
}
func testCollectionRailAddButtonCreatesEmptyCollection() {
let fixture = makePanelFixture()
@@ -414,6 +436,29 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum card"])
}
func testKeyboardCancelClearsSearchFromFocusedCard() {
let fixture = makePanelFixture()
fixture.store.upsert(makeTextItem("Alpha note", store: fixture.store))
fixture.store.upsert(makeTextItem("Quantum card", store: fixture.store))
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
fixture.view.debugSetSearchFieldText("quantum")
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum card"])
XCTAssertTrue(fixture.view.debugFocusCard(at: 0))
XCTAssertTrue(fixture.view.clearSearchForKeyboardCancel())
drainMainQueue()
fixture.window.contentView?.layoutSubtreeIfNeeded()
XCTAssertTrue(fixture.view.isSearchFieldEditing)
XCTAssertEqual(fixture.view.debugSearchFieldText, "")
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum card", "Alpha note"])
XCTAssertFalse(fixture.view.clearSearchForKeyboardCancel())
}
func testFocusedPreviewableCardSpaceOpensQuickLook() {
let fixture = makePanelFixture()
fixture.store.upsert(makeItem(kind: .url, text: "https://example.com/read", store: fixture.store))