gitbay/Views/Shared/RemovableChips.swift

v1.8.0
gitbay-ios/gitbay/Views/Shared/RemovableChips.swift history · blame · raw

50 lines · 2033 bytes

 1import SwiftUI
 2
 3/// A horizontal row of chips, each with a remove button: an issue's
 4/// labels and assignees, a merge request's labels. The remove button is
 5/// identified as `<idPrefix>-remove-<item>`.
 6struct RemovableChips: View {
 7
 8    let items: [String]
 9    let idPrefix: String
10    let disabled: Bool
11    var color: (String) -> Color = { _ in .secondary }
12    let remove: (String) -> Void
13
14    /// Extends the remove button's hit area to about 44pt without
15    /// changing the chip's layout.
16    private static let hitPadding: CGFloat = 16
17
18    var body: some View {
19        if !items.isEmpty {
20            ScrollView(.horizontal, showsIndicators: false) {
21                HStack(spacing: 6) {
22                    ForEach(items, id: \.self) { item in
23                        HStack(spacing: 3) {
24                            Text(item)
25                            Button {
26                                remove(item)
27                            } label: {
28                                Image(systemName: "xmark.circle.fill")
29                                    .foregroundStyle(.tertiary)
30                                    .padding(Self.hitPadding)
31                                    .contentShape(Rectangle())
32                                    .padding(-Self.hitPadding)
33                            }
34                            .disabled(disabled)
35                            .accessibilityLabel("Remove \(item)")
36                            .accessibilityIdentifier("\(idPrefix)-remove-\(item)")
37                        }
38                        .font(.gbSans(.caption))
39                        .padding(.horizontal, 8)
40                        .padding(.vertical, 3)
41                        .background(color(item).opacity(0.07), in: gbChipShape)
42                        .overlay(gbChipShape.stroke(color(item).opacity(0.35), lineWidth: 1))
43                    }
44                }
45                .padding(.vertical, Self.hitPadding)
46            }
47            .padding(.vertical, -Self.hitPadding)
48        }
49    }
50}