Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

DON-788: Update BPKSearchInputSummary #2066

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
33 changes: 20 additions & 13 deletions Backpack-SwiftUI/AppSearchModal/Classes/BPKAppSearchModal.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,21 @@ public struct BPKAppSearchModal: View {
let title: String
@Binding var inputText: String
let inputPrefix: BPKSearchInputSummary.InputPrefix
let clearAction: BPKSearchInputSummary.ClearAction
let inputHint: String
let results: BPKAppSearchModalResults
let closeAccessibilityLabel: String
let onClose: () -> Void
private var textFieldState: TextFieldState = .default
@FocusState private var inputFieldIsFocussed: Bool

public init(
title: String,
inputText: Binding<String>,
inputHint: String,
results: BPKAppSearchModalResults,
closeAccessibilityLabel: String,
inputPrefix: BPKSearchInputSummary.InputPrefix = .icon(.search),
clearAction: BPKSearchInputSummary.ClearAction,
onClose: @escaping () -> Void
) {
self.title = title
Expand All @@ -44,6 +45,7 @@ public struct BPKAppSearchModal: View {
self.results = results
self.closeAccessibilityLabel = closeAccessibilityLabel
self.inputPrefix = inputPrefix
self.clearAction = clearAction
self.onClose = onClose
}

Expand All @@ -52,11 +54,7 @@ public struct BPKAppSearchModal: View {
makeNavigationBar(title: title, closeAccessibilityLabel: closeAccessibilityLabel, onClose: onClose)
.padding(.horizontal, .base)
if results.showTextField {
BPKSearchInputSummary(placeholder: inputHint, inputPrefix: inputPrefix, $inputText)
.inputState(textFieldState.inputState)
.focused($inputFieldIsFocussed)
.autocorrectionDisabled(true)
.padding(.horizontal, .base)
searchInputSummary
}
switch results {
case .loading(let loading):
Expand All @@ -76,6 +74,18 @@ public struct BPKAppSearchModal: View {
.background(.surfaceDefaultColor)
}

private var searchInputSummary: some View {
BPKSearchInputSummary(
placeholder: inputHint,
inputPrefix: inputPrefix,
clearAction: clearAction,
$inputText
)
.focused($inputFieldIsFocussed)
.autocorrectionDisabled(true)
.padding(.horizontal, .base)
}

func makeNavigationBar(
title: String,
closeAccessibilityLabel: String,
Expand All @@ -93,12 +103,6 @@ public struct BPKAppSearchModal: View {
.padding(.vertical, .md)
}

public func inputState(_ state: TextFieldState) -> BPKAppSearchModal {
var result = self
result.textFieldState = state
return result
}

private func onScroll(_ offset: CGPoint) {
inputFieldIsFocussed = false
}
Expand All @@ -125,6 +129,7 @@ struct BPKAppSearchModal_Previews: PreviewProvider {
)),
closeAccessibilityLabel: "Close",
inputPrefix: .icon(.search),
clearAction: .init(accessibilityLabel: "clear", action: {}),
onClose: { }
)
.previewDisplayName("Content")
Expand All @@ -136,6 +141,7 @@ struct BPKAppSearchModal_Previews: PreviewProvider {
results: .loading(.init(accessibilityLabel: "Loading")),
closeAccessibilityLabel: "Close",
inputPrefix: .text("From"),
clearAction: .init(accessibilityLabel: "clear", action: {}),
onClose: { }
)
.previewDisplayName("Loading")
Expand All @@ -152,6 +158,7 @@ struct BPKAppSearchModal_Previews: PreviewProvider {

)),
closeAccessibilityLabel: "Close",
clearAction: .init(accessibilityLabel: "clear", action: {}),
onClose: { }
)
.previewDisplayName("Error")
Expand Down
9 changes: 8 additions & 1 deletion Backpack-SwiftUI/AppSearchModal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ Example of a AppSearchModal in Content state:
import Backpack_SwiftUI
BPKAppSearchModal(
title: "Search Modal",
inputText: $myText,
inputPrefix: BPKSearchInputSummary.InputPrefix.text("Prefix")
clearAction: BPKSearchInputSummary.ClearAction(accessibilityLabel: "Clear", action: {}),
inputHint: "Search",
results: .content(.init(
sections: [ /* sections */ ],
shortcuts: [ /* shortcuts */ ]
)),
inputPrefix: BPKSearchInputSummary.InputPrefix.text("Prefix"),
clearAction: BPKSearchInputSummary.ClearAction(accessibilityLabel: "Clear", action: {}),
closeAccessibilityLabel: "Close",
onClose: { }
)
Expand All @@ -53,6 +56,8 @@ BPKAppSearchModal(
inputText: $myText,
inputHint: "Search",
results: .loading(.init(accessibilityLabel: "Loading")),
inputPrefix: BPKSearchInputSummary.InputPrefix.text("Prefix"),
clearAction: BPKSearchInputSummary.ClearAction(accessibilityLabel: "Clear", action: {}),
closeAccessibilityLabel: "Close",
onClose: { /* close modal*/ }
)
Expand All @@ -75,6 +80,8 @@ BPKAppSearchModal(

)),
closeAccessibilityLabel: "Close",
inputPrefix: BPKSearchInputSummary.InputPrefix.text("Prefix"),
clearAction: BPKSearchInputSummary.ClearAction(accessibilityLabel: "Clear", action: {}),
onClose: { /* close modal*/ }
)
```
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import SwiftUI
///
/// Use `inputState(_ state: State)` to change the state of the text field.
public struct BPKSearchInputSummary: View {

public enum InputPrefix {
case text(String)
case icon(BPKIcon)
Expand All @@ -35,22 +36,33 @@ public struct BPKSearchInputSummary: View {
@Binding private var text: String
@FocusState private var focused: Bool
private let placeholder: String
private let inputPrefix: InputPrefix
private var state: State = .default
private let inputPrefix: InputPrefix?
private var style: Style = .default

private let readOnly: Bool
private let clearAction: ClearAction

public struct ClearAction {
public let accessibilityLabel: String
public let action: () -> Void

public init(accessibilityLabel: String, action: @escaping () -> Void) {
self.accessibilityLabel = accessibilityLabel
self.action = action
}
}

/// Creates a `BPKSearchInputSummary`.
///
/// - Parameters:
/// - placeholder: The placeholder text to display when the text field is empty.
/// - inputPrefix: The prefix which would be displayed on the left of text input
/// - text: The text to display in the text field.
public init(
placeholder: String = "",
inputPrefix: InputPrefix = .icon(.search),
inputPrefix: InputPrefix? = nil,
clearAction: ClearAction,
readOnly: Bool = false,
_ text: Binding<String>
) {
self.placeholder = placeholder
self.inputPrefix = inputPrefix
self.clearAction = clearAction
self.readOnly = readOnly
self._text = text
}

Expand All @@ -60,42 +72,40 @@ public struct BPKSearchInputSummary: View {
.accessibilityHidden(true)
TextField(placeholder, text: $text, prompt: placeholderView)
.font(style: .bodyDefault)
.foregroundColor(state.textColor)
.disabled(state.isDisabled)
.foregroundColor(.textPrimaryColor)
.disabled(readOnly)
.accessibilityElement()
.accessibilityValue(text.isEmpty ? placeholder : text)
.accessibilityAddTraits(readOnly ? [] : .isSearchField)
.accessibilityAddTraits(style == .focused ? .isSelected : [])
.focused($focused)
.accessibilityAddTraits(.isSearchField)
.accessibilityLabel(placeholder)
.accessibilityIdentifier("search_field")
accessory
}
.frame(maxWidth: .infinity, minHeight: 48.0)
.padding(.horizontal, BPKSpacing.base)
.background(.surfaceDefaultColor)
.clipShape(RoundedRectangle(cornerRadius: .sm))
.outline(focused ? .textLinkColor : state.borderColor, cornerRadius: .sm, lineWidth: focused ? 2.0 : 1.0)
.clipShape(RoundedRectangle(cornerRadius: .md))
.outline(
isBorderHighlighted ? .textLinkColor : .lineColor,
cornerRadius: .md,
lineWidth: isBorderHighlighted ? 2.0 : 1.0
)

.if(!BPKFont.enableDynamicType, transform: {
$0.sizeCategory(.large)
})
}

@ViewBuilder
private var accessory: some View {
if let icon = state.icon {
if case let .clear(accessibilityLabel, action) = state {
Button(action: action) {
BPKIconView(icon.icon)
.foregroundColor(icon.color)
}
.accessibilityElement(children: .ignore)
.accessibilityLabel(accessibilityLabel)
.accessibilityAddTraits(.isButton)
.opacity(text.isEmpty ? 0.0 : 1.0)
} else {
BPKIconView(icon.icon)
.foregroundColor(icon.color)
.accessibilityHidden(true)
}
Button(action: clearAction.action) {
BPKIconView(.closeCircle)
.foregroundColor(.textSecondaryColor)
}
.accessibilityElement(children: .ignore)
.accessibilityLabel(clearAction.accessibilityLabel)
.accessibilityAddTraits(.isButton)
.opacity(text.isEmpty ? 0.0 : 1.0)
}

@ViewBuilder
Expand All @@ -106,21 +116,27 @@ public struct BPKSearchInputSummary: View {

@ViewBuilder
private var prefixView: some View {
switch inputPrefix {
case .text(let prefixText):
BPKText(prefixText, style: .bodyDefault)
.foregroundColor(.textSecondaryColor)
case .icon(let icon):
BPKIconView(icon)
.foregroundColor(.textPrimaryColor)
if let inputPrefix {
switch inputPrefix {
case .text(let prefixText):
BPKText(prefixText, style: .bodyDefault)
.foregroundColor(.textSecondaryColor)
case .icon(let icon):
BPKIconView(icon)
.foregroundColor(.textPrimaryColor)
}
}
}

public func inputState(_ state: State) -> BPKSearchInputSummary {
public func customStyle(_ style: Style) -> BPKSearchInputSummary {
var result = self
result.state = state
result.style = style
return result
}

private var isBorderHighlighted: Bool {
focused || style == .focused
}
}

fileprivate extension TextField {
Expand All @@ -131,19 +147,17 @@ fileprivate extension TextField {

struct BPKSearchInputSummary_Previews: PreviewProvider {
static var previews: some View {
// swiftlint:disable line_length
VStack {
BPKSearchInputSummary(.constant(""))
BPKSearchInputSummary(placeholder: "Enter", .constant(""))
BPKSearchInputSummary(.constant("Value"))
BPKSearchInputSummary(inputPrefix: .text("From"), .constant("Value"))
BPKSearchInputSummary(.constant("Disabled"))
.inputState(.disabled)
BPKSearchInputSummary(.constant("Value"))
.inputState(.error)
BPKSearchInputSummary(.constant("Value"))
.inputState(.clear(accessibilityLabel: "clear", action: {}))
BPKSearchInputSummary(.constant("Value"))
.inputState(.valid)
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant(""))
BPKSearchInputSummary(placeholder: "Enter", clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant(""))
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant("Value"))
BPKSearchInputSummary(inputPrefix: .text("From"), clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant("Value"))
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "Clear", action: {}), readOnly: true, .constant("Read Only"))
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant("Manually highlighted"))
.customStyle(.focused)
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "Clear", action: {}), .constant("Value"))
BPKSearchInputSummary(clearAction: .init(accessibilityLabel: "clear", action: {}), .constant("Value"))
}
.padding()
.background(.coreEcoColor)
Expand Down

This file was deleted.

Loading
Loading