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. 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. 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. 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. 13. Press `Esc` again and confirm the panel closes.
14. Reopen the panel, change sort segments, and confirm each segment updates results. 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. 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 { switch event.keyCode {
case 53: case 53:
self.hide() if !self.panelView.clearSearchForKeyboardCancel() {
self.hide()
}
return nil return nil
case 49: case 49:
self.previewSelected() self.previewSelected()

View File

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

View File

@@ -263,6 +263,28 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum reference"]) 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() { func testCollectionRailAddButtonCreatesEmptyCollection() {
let fixture = makePanelFixture() let fixture = makePanelFixture()
@@ -414,6 +436,29 @@ final class ClipboardPanelViewTests: XCTestCase {
XCTAssertEqual(fixture.viewModel.visibleItems.map(\.payload), ["Quantum card"]) 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() { func testFocusedPreviewableCardSpaceOpensQuickLook() {
let fixture = makePanelFixture() let fixture = makePanelFixture()
fixture.store.upsert(makeItem(kind: .url, text: "https://example.com/read", store: fixture.store)) fixture.store.upsert(makeItem(kind: .url, text: "https://example.com/read", store: fixture.store))