gitbay/Views/Shared/RemovableChips.swift
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}