Keep toolbar search field stable

This commit is contained in:
Kaede Akino committed 2026-08-29 02:17:36 +08:00
1 parent ad73c5db5b
commit 7bc4a4e92e
1 file changed
+15 -1
+15 -1
View File
@@ -53,6 +53,15 @@ struct WindowToolbarFindContext {
// MARK: - The field
/// One native field for the lifetime of the toolbar item. SwiftUI's macOS
/// toolbar bridge may rebuild the representable as its binding changes; reusing
/// the AppKit control prevents the focus ring and field editor from being torn
/// down and redrawn for every character.
@MainActor
final class NativeSearchFieldOwner {
let field = NSSearchField()
}
/// `NSSearchField`, not `.searchable`.
///
/// `.searchable` gives no access to `searchMenuTemplate`, which is where the
@@ -61,6 +70,9 @@ struct WindowToolbarFindContext {
struct NativeSearchField: NSViewRepresentable {
@Binding var text: String
var placeholder: String
/// Supplied by the window toolbar. Sidebar search fields omit it and own an
/// ordinary representable-scoped control.
var owner: NativeSearchFieldOwner? = nil
/// `.large` for the sidebar footer, whose field is the whole footer.
/// `NSSearchField` stretches its bezel to an explicit frame height, so the
/// capsule is the size it is given — and on macOS 26 that capsule is the
@@ -93,7 +105,7 @@ struct NativeSearchField: NSViewRepresentable {
func makeCoordinator() -> Coordinator { Coordinator(field: self) }
func makeNSView(context: Context) -> NSSearchField {
let field = NSSearchField()
let field = owner?.field ?? NSSearchField()
field.delegate = context.coordinator
field.placeholderString = placeholder
field.stringValue = text
@@ -409,6 +421,7 @@ struct NativeSearchField: NSViewRepresentable {
/// Welcome and on a workspace that has no searchable pane in front.
struct WindowToolbarFindField: View {
@Environment(WindowModel.self) private var window
@State private var searchFieldOwner = NativeSearchFieldOwner()
var body: some View {
Group {
@@ -416,6 +429,7 @@ struct WindowToolbarFindField: View {
NativeSearchField(
text: context.query,
placeholder: String(localized: "Search"),
owner: searchFieldOwner,
focusRequest: context.focusRequest,
maintainsKeyboardFocus: window.isToolbarFindFocused,
navigate: context.navigate,