Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[PBIOS-611] Turn selected into binding #464

Merged
merged 3 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 37 additions & 40 deletions Sources/Playbook/Components/Typeahead/PBTypeahead.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ public struct PBTypeahead<Content: View>: View {
private let title: String
private let placeholder: String
private let selection: Selection
private let noOptionsText: String
private let debounce: (time: TimeInterval, numberOfCharacters: Int)
private let dropdownMaxHeight: CGFloat?
private let listOffset: (x: CGFloat, y: CGFloat)
private let popoverManager = PopoverManager()
private let clearAction: (() -> Void)?
private let noOptionsText: String
private let onSelection: (([Option]) -> Void)?
private let popoverManager = PopoverManager()

@State private var showList: Bool = false
@State private var isCollapsed = false
@State private var hoveringIndex: Int?
Expand All @@ -31,7 +31,7 @@ public struct PBTypeahead<Content: View>: View {
@State private var selectedIndex: Int?
@State private var focused: Bool = false
@Binding var options: [Option]
@State private var selectedOptions: [Option]
@Binding var selectedOptions: [Option]
@Binding var searchText: String
@FocusState.Binding private var isFocused: Bool

Expand All @@ -46,10 +46,9 @@ public struct PBTypeahead<Content: View>: View {
dropdownMaxHeight: CGFloat? = nil,
listOffset: (x: CGFloat, y: CGFloat) = (0, 0),
isFocused: FocusState<Bool>.Binding,
selectedOptions: [Option] = [],
noOptionsText: String = "No options",
selectedOptions: Binding<[Option]>,
clearAction: (() -> Void)? = nil,
onSelection: (([Option]) -> Void)? = nil
noOptionsText: String = "No options"
) {
self.id = id
self.title = title
Expand All @@ -63,8 +62,7 @@ public struct PBTypeahead<Content: View>: View {
self._isFocused = isFocused
self.clearAction = clearAction
self.noOptionsText = noOptionsText
self.selectedOptions = selectedOptions
self.onSelection = onSelection
self._selectedOptions = selectedOptions
}

public var body: some View {
Expand Down Expand Up @@ -95,7 +93,6 @@ public struct PBTypeahead<Content: View>: View {
}
}
.onAppear {
onSelection?(selectedOptions)
focused = isFocused
if debounce.numberOfCharacters == 0 {
showList = isFocused
Expand Down Expand Up @@ -136,32 +133,7 @@ private extension PBTypeahead {
ScrollView {
VStack(spacing: 0) {
ForEach(Array(zip(searchResults.indices, searchResults)), id: \.0) { index, result in
HStack {
if result.0 == noOptionsText {
emptyView
} else {
if let customView = result.1?.1?() {
customView
} else {
Text(result.1?.0 ?? result.0)
.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 = result
}
.onTapGesture {
if result.0 != "No Options" {
onListSelection(index: index, option: result)
}
}
listCell(index: index, option: result)
}
}
}
Expand All @@ -174,6 +146,35 @@ private extension PBTypeahead {
.transition(.opacity)
}

func listCell(index: Int, option: Option) -> some View {
HStack {
if option.0 == noOptionsText {
emptyView
} else {
if let customView = option.1?.1?() {
customView
} else {
Text(option.1?.0 ?? option.0)
.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 {
if option.0 != "No Options" {
onListSelection(index: index, option: option)
}
}
}

var emptyView: some View {
HStack {
Spacer()
Expand Down Expand Up @@ -222,7 +223,6 @@ private extension PBTypeahead {
var clearText: Void {
searchText = ""
selectedOptions.removeAll()
onSelection?([])
selectedOptions = []
selectedIndex = nil
hoveringIndex = nil
Expand Down Expand Up @@ -305,20 +305,17 @@ private extension PBTypeahead {
selectedIndex = index
hoveringIndex = index
selectedOptions.append(option)
onSelection?(selectedOptions)
}

func onMultipleSelection(_ option: Option) {
selectedOptions.append(option)
onSelection?(selectedOptions)
hoveringIndex = nil
selectedIndex = nil
}

func removeSelected(_ index: Int) {
if let selectedElementIndex = selectedOptions.indices.first(where: { $0 == index }) {
let _ = selectedOptions.remove(at: selectedElementIndex)
onSelection?(selectedOptions)
selectedIndex = nil
}
}
Expand Down
17 changes: 8 additions & 9 deletions Sources/Playbook/Components/Typeahead/TypeaheadCatalog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import SwiftUI

public struct TypeaheadCatalog: View {
@State private var assetsColors = Mocks.assetsColors
@State private var selectedColors: [(String, (String, (() -> AnyView?)?)?)] = []
@State private var selectedAssetsColors: [(String, (String, (() -> AnyView?)?)?)] = []
@State private var assetsUsers = Mocks.multipleUsersDictionary
@State private var selectedUsers: [(String, (String, (() -> PBUser?)?)?)] = [
Expand Down Expand Up @@ -84,9 +85,9 @@ extension TypeaheadCatalog {
searchText: $searchTextColors,
options: $assetsColors,
selection: .single,
isFocused: $isFocused1) { value in
print(value.first?.0)
}
isFocused: $isFocused1,
selectedOptions: $selectedColors
)
}

var users: some View {
Expand All @@ -98,10 +99,8 @@ extension TypeaheadCatalog {
options: $assetsUsers,
selection: .multiple(variant: .pill),
isFocused: $isFocused2,
selectedOptions: selectedUsers
) { options in
print("Selected options \(options)")
}
selectedOptions: $selectedUsers
)
}

var heightAdjusted: some View {
Expand All @@ -114,7 +113,7 @@ extension TypeaheadCatalog {
selection: .multiple(variant: .pill),
dropdownMaxHeight: 150,
isFocused: $isFocused3,
selectedOptions: selectedUsers1
selectedOptions: $selectedUsers1
)
}

Expand Down Expand Up @@ -174,7 +173,7 @@ extension TypeaheadCatalog {
selection: .multiple(variant: .pill),
dropdownMaxHeight: 300,
isFocused: $isFocused,
selectedOptions: selectedUsers
selectedOptions: $selectedUsers
)
Spacer()
}
Expand Down