Skip to content

Commit

Permalink
Various a11y fixes for SearchBar and BadgeView (microsoft#2054)
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-cap authored and keitayer committed Jul 16, 2024
1 parent f399a76 commit def6cfd
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class SearchBarDemoController: DemoController, SearchBarDelegate {
private struct Constants {
static let badgeViewCornerRadius: CGFloat = 10
static let badgeViewSideLength: CGFloat = 20
static let badgeViewMaxFontSize: CGFloat = 40
static let searchBarStackviewMargin: CGFloat = 16
}

Expand Down Expand Up @@ -110,7 +109,7 @@ class SearchBarDemoController: DemoController, SearchBarDelegate {
badge.tokenSet[.backgroundDisabledColor] = .uiColor { .init(light: GlobalTokens.sharedColor(.purple, .primary)) }
badge.tokenSet[.foregroundDisabledColor] = .uiColor { .init(light: GlobalTokens.neutralColor(.white)) }
badge.isActive = false
badge.maxFontSize = Constants.badgeViewMaxFontSize
badge.showsLargeContentViewer = true
return badge
}

Expand Down
4 changes: 3 additions & 1 deletion ios/FluentUI/Badge Field/BadgeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,9 @@ open class BadgeView: UIView, TokenizedControlInternal {
}

func reload() {
label.text = dataSource?.text
let text = dataSource?.text
label.text = text
largeContentTitle = text
style = dataSource?.style ?? .default
sizeCategory = dataSource?.sizeCategory ?? .medium

Expand Down
44 changes: 33 additions & 11 deletions ios/FluentUI/Navigation/SearchBar/SearchBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ open class SearchBar: UIView, TokenizedControlInternal {
textField.accessibilityTraits = .searchField
textField.addTarget(self, action: #selector(searchTextFieldValueDidChange(_:)), for: .editingChanged)
textField.showsLargeContentViewer = true
textField.adjustsFontForContentSizeCategory = true

if #available(iOS 17, *) {
textField.hoverStyle = nil
}
Expand Down Expand Up @@ -124,6 +126,11 @@ open class SearchBar: UIView, TokenizedControlInternal {
clearButton.addTarget(self, action: #selector(SearchBar.clearButtonTapped(sender:)), for: .touchUpInside)
clearButton.setImage(UIImage.staticImageNamed("search-clear"), for: .normal)
clearButton.isHidden = true
clearButton.showsLargeContentViewer = true

let clearLabel = "Accessibility.TextField.ClearText".localized
clearButton.accessibilityLabel = clearLabel
clearButton.largeContentTitle = clearLabel

clearButton.isPointerInteractionEnabled = true
clearButton.pointerStyleProvider = { button, _, _ in
Expand All @@ -144,6 +151,7 @@ open class SearchBar: UIView, TokenizedControlInternal {
button.addTarget(self, action: #selector(SearchBar.cancelButtonTapped(sender:)), for: .touchUpInside)
button.alpha = 0.0
button.showsLargeContentViewer = true
button.titleLabel?.adjustsFontForContentSizeCategory = true
button.isPointerInteractionEnabled = true
if #available(iOS 17, *) {
button.hoverStyle = UIHoverStyle(shape: .capsule)
Expand Down Expand Up @@ -280,6 +288,10 @@ open class SearchBar: UIView, TokenizedControlInternal {
private func setupLayout() {
addInteraction(UILargeContentViewerInteraction())

// Search bar has fixed height, so this is the largest size category we can handle while still being usable.
// The larger edge cases are covered by large content viewer.
maximumContentSizeCategory = .accessibilityMedium

// Autolayout is more efficent if all constraints are activated simultaneously
var constraints = [NSLayoutConstraint]()

Expand Down Expand Up @@ -317,10 +329,24 @@ open class SearchBar: UIView, TokenizedControlInternal {
searchTextFieldBackgroundView.addSubview(searchTextField)
searchTextField.translatesAutoresizingMaskIntoConstraints = false

constraints.append(searchTextField.centerYAnchor.constraint(equalTo: searchTextFieldBackgroundView.centerYAnchor))
constraints.append(searchTextField.heightAnchor.constraint(equalTo: searchTextFieldBackgroundView.heightAnchor, constant: -2 * SearchBarTokenSet.searchTextFieldVerticalInset))
constraints.append(searchTextField.leadingAnchor.constraint(equalTo: searchIconImageViewContainerView.trailingAnchor, constant: SearchBarTokenSet.searchTextFieldLeadingInset))
textFieldLeadingConstraint = constraints.last
// This lets leadingView squeeze the searchTextField when needed.
searchTextField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

// This imposes a limit on how much the leadingView can squeeze the input field
let searchTextFieldMinWidthConstraint = searchTextField.widthAnchor.constraint(greaterThanOrEqualToConstant: SearchBarTokenSet.searchTextFieldInteractionMinWidth)

// The min width is important, but we don't want to override other constraints the parent may impose on us.
searchTextFieldMinWidthConstraint.priority = .defaultHigh

let searchTextFieldLeadingConstraint = searchTextField.leadingAnchor.constraint(equalTo: searchIconImageViewContainerView.trailingAnchor, constant: SearchBarTokenSet.searchTextFieldLeadingInset)
textFieldLeadingConstraint = searchTextFieldLeadingConstraint

constraints.append(contentsOf: [
searchTextField.centerYAnchor.constraint(equalTo: searchTextFieldBackgroundView.centerYAnchor),
searchTextField.heightAnchor.constraint(equalTo: searchTextFieldBackgroundView.heightAnchor, constant: -2 * SearchBarTokenSet.searchTextFieldVerticalInset),
searchTextFieldLeadingConstraint,
searchTextFieldMinWidthConstraint
])

// progressSpinner
let progressSpinnerView = progressSpinner
Expand Down Expand Up @@ -363,18 +389,14 @@ open class SearchBar: UIView, TokenizedControlInternal {
}

searchTextFieldBackgroundView.addSubview(leadingView)

let leadingViewRenderWidth = searchTextFieldBackgroundView.frame.size.width - SearchBarTokenSet.searchIconInsettedWidth - SearchBarTokenSet.searchTextFieldLeadingInset - SearchBarTokenSet.searchTextFieldInteractionMinWidth - SearchBarTokenSet.clearButtonInsettedWidth
let leadingViewRenderSize = CGSize(width: leadingViewRenderWidth, height: searchTextFieldBackgroundView.frame.size.height)
let leadingViewSize = leadingView.sizeThatFits(leadingViewRenderSize)
leadingView.setContentHuggingPriority(.required, for: .horizontal)
leadingView.translatesAutoresizingMaskIntoConstraints = false

NSLayoutConstraint.activate([
leadingView.heightAnchor.constraint(lessThanOrEqualToConstant: SearchBarTokenSet.searchTextFieldBackgroundHeight),
leadingView.leadingAnchor.constraint(equalTo: searchIconImageViewContainerView.trailingAnchor, constant: SearchBarTokenSet.searchIconInset),
leadingView.trailingAnchor.constraint(equalTo: searchTextField.leadingAnchor, constant: -SearchBarTokenSet.searchTextFieldLeadingInset),
leadingView.centerYAnchor.constraint(equalTo: searchTextFieldBackgroundView.centerYAnchor),
leadingView.widthAnchor.constraint(equalToConstant: leadingViewSize.width),
leadingView.heightAnchor.constraint(equalToConstant: leadingViewSize.height)
leadingView.centerYAnchor.constraint(equalTo: searchTextFieldBackgroundView.centerYAnchor)
])
}

Expand Down

0 comments on commit def6cfd

Please sign in to comment.