diff --git a/Sources/Playbook/Components/Popover/PopoverHandler.swift b/Sources/Playbook/Components/Popover/PopoverHandler.swift index 262d3f108..1fc226471 100644 --- a/Sources/Playbook/Components/Popover/PopoverHandler.swift +++ b/Sources/Playbook/Components/Popover/PopoverHandler.swift @@ -12,6 +12,7 @@ import SwiftUI struct PopoverView: View { let id: Int let blockBackgroundInteractions: Bool + @State private var opacity: CGFloat = 0.01 @EnvironmentObject var popoverManager: PopoverManager init( @@ -35,6 +36,16 @@ struct PopoverView: View { .onTapGesture { popoverManager.closeInside(id) } + .onAppear { + if popover?.position != nil { + Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false) { _ in + opacity = 1 + } + } else { + opacity = 0.01 + } + } + .opacity(opacity) } } } diff --git a/Sources/Playbook/Components/Typeahead/GridInputField.swift b/Sources/Playbook/Components/Typeahead/GridInputField.swift index 3d1f24d4d..3de49fc71 100644 --- a/Sources/Playbook/Components/Typeahead/GridInputField.swift +++ b/Sources/Playbook/Components/Typeahead/GridInputField.swift @@ -16,11 +16,11 @@ public struct GridInputField: View { private let onItemTap: ((Int) -> Void)? private let onViewTap: (() -> Void)? private let shape = RoundedRectangle(cornerRadius: BorderRadius.medium) + private var isFocused: FocusState.Binding @Binding var searchText: String @State private var isHovering: Bool = false @State private var clearButtonIsHovering: Bool = false @State private var indicatorIsHovering: Bool = false - var isFocused: FocusState.Binding init( placeholder: String = "Select", @@ -52,22 +52,9 @@ public struct GridInputField: View { ForEach(indices, id: \.self) { index in if indices.last != index { gridView(index: index) - } else { - textfieldWithCustomPlaceholder - .fixedSize() - .frame(minWidth: 60, alignment: .leading) - .overlay { - Color.white - .opacity(isFocused.wrappedValue ? 0.001 : 0) - .onTapGesture { - if isFocused.wrappedValue { - onViewTap?() - } - } - } - .clipped() } } + textfieldWithCustomPlaceholder } .padding(.horizontal, Spacing.small) .padding(.vertical, Spacing.xSmall) @@ -114,7 +101,20 @@ private extension GridInputField { } .textFieldStyle(.plain) .pbFont(.body, color: textColor) + .frame(height: 24) } + .fixedSize() + .frame(minWidth: 60, alignment: .leading) + .overlay { + Color.white + .opacity(isFocused.wrappedValue ? 0.001 : 0) + .onTapGesture { + if isFocused.wrappedValue { + onViewTap?() + } + } + } + .clipped() } func gridView(index: Int?) -> AnyView? { @@ -254,13 +254,13 @@ public struct WrappedInputFieldCatalog: View { GridInputField( searchText: $text, - selection: .multiple(.pill, ["title1", "title2", "title2", "title2", "title2"]), + selection: .multiple(.pill, ["title1", "title2", "title2"]), isFocused: $isFocused ) GridInputField( searchText: $text, - selection: .multiple(.other(AnyView(PBPill("oi", variant: .primary))), ["title1", "title2", "title2", "title2", "title2", "title2", "title2", "title2"]), + selection: .multiple(.other(AnyView(PBPill("oi", variant: .primary))), ["title1", "title2", "title2"]), isFocused: $isFocused ) diff --git a/Sources/Playbook/Components/Typeahead/PBTypeahead.swift b/Sources/Playbook/Components/Typeahead/PBTypeahead.swift index 34931eeb7..b4f69b8cc 100644 --- a/Sources/Playbook/Components/Typeahead/PBTypeahead.swift +++ b/Sources/Playbook/Components/Typeahead/PBTypeahead.swift @@ -26,7 +26,6 @@ public struct PBTypeahead: View { @State private var hoveringIndex: Int? @State private var hoveringOption: Typeahead.Option? @State private var isHovering: Bool = false - @State private var contentSize: CGSize = .zero @State private var selectedIndex: Int? @State private var focused: Bool = false @Binding var selectedOptions: [Typeahead.Option] @@ -76,7 +75,6 @@ public struct PBTypeahead: View { onItemTap: { removeSelected($0) }, onViewTap: { onViewTap } ) - .sizeReader { contentSize = $0 } .pbPopover( isPresented: $showList, id: id, @@ -96,30 +94,22 @@ public struct PBTypeahead: View { showList = isFocused } setKeyboardControls - selectedIndex = options.firstIndex(of: selectedOptions[0]) - } - .onChange(of: isFocused) { newValue in - Timer.scheduledTimer(withTimeInterval: 0.1, repeats: false) { _ in - showList = newValue + if !selectedOptions.isEmpty { + selectedIndex = options.firstIndex(of: selectedOptions[0]) } } - .onChange(of: searchText, debounce: debounce) { _ in - _ = searchResults - reloadList - } - .onChange(of: options.count) { _ in - reloadList - } - .onChange(of: searchResults.count) { _ in - reloadList + .onChange(of: isFocused) { newValue in + showList = newValue } - .onChange(of: contentSize) { _ in + .onChange(of: selectedOptions.count) { _ in reloadList } .onChange(of: hoveringIndex) { index in reloadList } .onChange(of: searchText, debounce: debounce) { _ in + _ = searchResults + reloadList if !searchText.isEmpty { showList = true } @@ -142,9 +132,7 @@ private extension PBTypeahead { .scrollDismissesKeyboard(.immediately) .frame(maxHeight: dropdownMaxHeight) .fixedSize(horizontal: false, vertical: true) - .frame(maxWidth: .infinity, alignment: .top) } - .frame(maxWidth: .infinity, alignment: .top) } func listItemView(index: Int, option: Typeahead.Option) -> some View { @@ -152,26 +140,26 @@ private extension PBTypeahead { if option.text == noOptionsText { emptyView } else { - if let customView = option.customView?() { - customView - } else { - Text(option.text ?? option.id) - .pbFont(.body, color: listTextolor(index)) + Group { + if let customView = option.customView?() { + customView + } else { + Text(option.text ?? option.id) + .pbFont(.body, color: listTextolor(index)) + } + } + .padding(.horizontal, Spacing.xSmall + 4) + .padding(.vertical, Spacing.xSmall + 4) + .frame(maxWidth: .infinity, alignment: .leading) + .background(listBackgroundColor(index)) + .onHover(disabled: false) { hover in + isHovering = hover + hoveringIndex = index + hoveringOption = option + } + .onTapGesture { + onListSelection(index: index, option: option) } - } - } - .padding(.horizontal, Spacing.xSmall + 4) - .padding(.vertical, Spacing.xSmall + 4) - .frame(maxWidth: .infinity, alignment: .leading) - .background(listBackgroundColor(index)) - .onHover(disabled: false) { hover in - isHovering = hover - hoveringIndex = index - hoveringOption = option - } - .onTapGesture { - if option.text != noOptionsText { - onListSelection(index: index, option: option) } } } @@ -183,6 +171,8 @@ private extension PBTypeahead { .pbFont(.body, color: .text(.light)) Spacer() } + .padding(.horizontal, Spacing.xSmall + 4) + .padding(.vertical, Spacing.xSmall + 4) } var searchResults: [Typeahead.Option] { @@ -230,13 +220,11 @@ private extension PBTypeahead { } var reloadList: Void { - if showList { - isHovering.toggle() - } + isHovering.toggle() } func onListSelection(index: Int, option: Typeahead.Option) { - if showList { + if showList, option.text != noOptionsText { switch selection { case .single: onSingleSelection(index: index, option) @@ -246,6 +234,7 @@ private extension PBTypeahead { } showList = false searchText = "" + reloadList } func onSingleSelection(index: Int, _ option: Typeahead.Option) { @@ -266,7 +255,9 @@ private extension PBTypeahead { if let selectedElementIndex = selectedOptions.indices.first(where: { $0 == index }) { let _ = selectedOptions.remove(at: selectedElementIndex) selectedIndex = nil + hoveringIndex = nil } + reloadList } func listBackgroundColor(_ index: Int?) -> Color {