Skip to content

Commit

Permalink
Merge pull request #785 from kiwicom/595-replace-tagstyle
Browse files Browse the repository at this point in the history
Replace `TagStyle` with `removeAction`
  • Loading branch information
sjavora authored Mar 26, 2024
2 parents 69d62ff + 7568b7f commit ccb07a4
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 86 deletions.
84 changes: 33 additions & 51 deletions Sources/Orbit/Components/Tag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import SwiftUI
///
/// ```swift
/// Tag("Sorting", icon: .sort, isSelected: $isSortingApplied)
/// Tag("Filters", style: .removable(action: { /* Tap action */ }), isSelected: $isFiltersApplied)
/// Tag("Filters", isSelected: $isFiltersApplied) {
/// // Tap action
/// }
/// ```
///
/// ### Customizing appearance
Expand Down Expand Up @@ -34,10 +36,10 @@ public struct Tag<Icon: View>: View, PotentiallyEmptyView {
@Environment(\.isHapticsEnabled) private var isHapticsEnabled

private let label: String
private let style: TagStyle
private let isFocused: Bool
@Binding private var isSelected: Bool
@ViewBuilder private let icon: Icon
private let removeAction: (() -> Void)?

public var body: some View {
if isEmpty == false {
Expand Down Expand Up @@ -67,11 +69,7 @@ public struct Tag<Icon: View>: View, PotentiallyEmptyView {
}
}
.buttonStyle(
TagButtonStyle(
style: style,
isFocused: isFocused,
isSelected: isSelected
)
TagButtonStyle(isFocused: isFocused, isSelected: isSelected, removeAction: removeAction)
)
.accessibility(addTraits: isSelected ? .isSelected : [])
}
Expand All @@ -88,52 +86,36 @@ public extension Tag {
/// Creates Orbit ``Tag`` component with custom leading icon.
init(
_ label: String = "",
style: TagStyle = .default,
isFocused: Bool = true,
isSelected: Binding<Bool>,
@ViewBuilder icon: () -> Icon
@ViewBuilder icon: () -> Icon,
removeAction: (() -> Void)? = nil
) {
self.label = label
self.style = style
self.isFocused = isFocused
self._isSelected = isSelected
self.icon = icon()
self.removeAction = removeAction
}

/// Creates Orbit ``Tag`` component.
init(
_ label: String = "",
icon: Icon.Symbol? = nil,
style: TagStyle = .default,
isFocused: Bool = true,
isSelected: Binding<Bool>
isSelected: Binding<Bool>,
removeAction: (() -> Void)? = nil
) where Icon == Orbit.Icon {
self.init(
label,
style: style,
isFocused: isFocused,
isSelected: isSelected
) {
Icon(icon)
.iconSize(textSize: .normal)
}
}
}

// MARK: - Types

/// Orbit ``Tag`` style.
public enum TagStyle: Equatable {

case `default`
case removable(action: () -> Void)

public static func == (lhs: TagStyle, rhs: TagStyle) -> Bool {
switch (lhs, rhs) {
case (.default, .default): return true
case (.removable, .removable): return true
default: return false
}
isSelected: isSelected,
icon: {
Icon(icon)
.iconSize(textSize: .normal)
},
removeAction: removeAction
)
}
}

Expand All @@ -154,7 +136,7 @@ struct TagPreviews: PreviewProvider {

static var standalone: some View {
StateWrapper(true) { isSelected in
Tag(label, icon: .grid, style: .removable(action: {}), isSelected: isSelected)
Tag(label, icon: .grid, isSelected: isSelected, removeAction: {})
Tag("", isSelected: .constant(false)) // EmptyView
}
.padding(.medium)
Expand All @@ -163,7 +145,7 @@ struct TagPreviews: PreviewProvider {

static var standaloneExpanding: some View {
StateWrapper(true) { isSelected in
Tag(label, icon: .grid, style: .removable(action: {}), isSelected: isSelected)
Tag(label, icon: .grid, isSelected: isSelected, removeAction: {})
.idealSize(horizontal: false)
}
.padding(.medium)
Expand All @@ -172,17 +154,17 @@ struct TagPreviews: PreviewProvider {

static var styles: some View {
VStack(alignment: .leading, spacing: .large) {
stack(style: .default, isFocused: true)
stack(style: .default, isFocused: false)
stack(style: .removable(action: {}), isFocused: true)
stack(style: .removable(action: {}), isFocused: false)
stack(isRemovable: false, isFocused: true)
stack(isRemovable: false, isFocused: false)
stack(isRemovable: true, isFocused: true)
stack(isRemovable: true, isFocused: false)
Separator()
stack(style: .default, isFocused: false, idealWidth: false)
stack(style: .removable(action: {}), isFocused: true, idealWidth: false)
stack(isRemovable: false, isFocused: false, idealWidth: false)
stack(isRemovable: true, isFocused: true, idealWidth: false)
Separator()
HStack(spacing: .medium) {
StateWrapper(true) { isSelected in
Tag(label, icon: .sort, style: .removable(action: {}), isSelected: isSelected)
Tag(label, icon: .sort, isSelected: isSelected, removeAction: {})
}
StateWrapper(false) { isSelected in
Tag(icon: .notificationAdd, isFocused: false, isSelected: isSelected)
Expand All @@ -206,23 +188,23 @@ struct TagPreviews: PreviewProvider {
.previewDisplayName()
}

static func stack(style: TagStyle, isFocused: Bool, idealWidth: Bool? = nil) -> some View {
static func stack(isRemovable: Bool, isFocused: Bool, idealWidth: Bool? = nil) -> some View {
HStack(spacing: .medium) {
VStack(spacing: .small) {
tag(style: style, isFocused: isFocused, isSelected: false)
tag(style: style, isFocused: isFocused, isSelected: true)
tag(isRemovable: isRemovable, isFocused: isFocused, isSelected: false)
tag(isRemovable: isRemovable, isFocused: isFocused, isSelected: true)
}
}
.idealSize(horizontal: idealWidth)
}

static func tag(style: TagStyle, isFocused: Bool, isSelected: Bool) -> some View {
StateWrapper((style, isSelected, true)) { state in
static func tag(isRemovable: Bool, isFocused: Bool, isSelected: Bool) -> some View {
StateWrapper((isRemovable, isSelected, true)) { state in
Tag(
label,
style: style == .default ? .default : .removable(action: { state.wrappedValue.2 = false }),
isFocused: isFocused,
isSelected: state.1
isSelected: state.1,
removeAction: state.0.wrappedValue ? { state.wrappedValue.2 = false } : nil
)
.opacity(state.wrappedValue.2 ? 1 : 0)
}
Expand Down
42 changes: 21 additions & 21 deletions Sources/Orbit/Support/ButtonStyles/TagButtonStyle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ public struct TagButtonStyle: ButtonStyle {
@Environment(\.backgroundShape) private var backgroundShape
@Environment(\.iconColor) private var iconColor
@Environment(\.textColor) private var textColor

private let style: TagStyle

private let isFocused: Bool
private let isSelected: Bool
private let removeAction: (() -> Void)?

public func makeBody(configuration: Configuration) -> some View {
HStack(spacing: .xSmall) {
Expand All @@ -21,7 +21,7 @@ public struct TagButtonStyle: ButtonStyle {
.textColor(resolvedTextColor)
.lineLimit(1)

if case .removable(let removeAction) = style {
if let removeAction {
Icon(.closeCircle)
.iconSize(.small)
.iconColor(resolvedIconColor(isPressed: configuration.isPressed))
Expand Down Expand Up @@ -110,13 +110,13 @@ public struct TagButtonStyle: ButtonStyle {

/// Create button style for Orbit ``Tag`` component.
public init(
style: TagStyle,
isFocused: Bool,
isSelected: Bool
isSelected: Bool,
removeAction: (() -> Void)?
) {
self.style = style
self.isFocused = isFocused
self.isSelected = isSelected
self.removeAction = removeAction
}
}

Expand All @@ -134,25 +134,25 @@ struct TagButtonStylePreviews: PreviewProvider {
static var styles: some View {
VStack(alignment: .leading, spacing: .medium) {
button
.buttonStyle(TagButtonStyle(style: .default, isFocused: false, isSelected: false))
.buttonStyle(TagButtonStyle(isFocused: false, isSelected: false, removeAction: nil))

button
.buttonStyle(TagButtonStyle(style: .default, isFocused: true, isSelected: false))
.buttonStyle(TagButtonStyle(isFocused: true, isSelected: false, removeAction: nil))

button
.buttonStyle(TagButtonStyle(style: .default, isFocused: true, isSelected: true))
.buttonStyle(TagButtonStyle(isFocused: true, isSelected: true, removeAction: nil))

button
.buttonStyle(TagButtonStyle(style: .removable(action: {}), isFocused: true, isSelected: false))
.buttonStyle(TagButtonStyle(isFocused: true, isSelected: false, removeAction: {}))

button
.buttonStyle(TagButtonStyle(style: .removable(action: {}), isFocused: true, isSelected: true))
.buttonStyle(TagButtonStyle(isFocused: true, isSelected: true, removeAction: {}))

button
.buttonStyle(TagButtonStyle(style: .removable(action: {}), isFocused: false, isSelected: false))
.buttonStyle(TagButtonStyle(isFocused: false, isSelected: false, removeAction: {}))

button
.buttonStyle(TagButtonStyle(style: .removable(action: {}), isFocused: false, isSelected: true))
.buttonStyle(TagButtonStyle(isFocused: false, isSelected: true, removeAction: {}))
}
.previewDisplayName()
}
Expand All @@ -171,11 +171,11 @@ struct TagButtonStylePreviews: PreviewProvider {
.backgroundStyle(Gradient.bundleBasic.background, active: .redLight)

button
.buttonStyle(TagButtonStyle(style: .removable(action: {}), isFocused: true, isSelected: true))
.buttonStyle(TagButtonStyle(isFocused: true, isSelected: true, removeAction: {}))
.iconColor(.blueLight)
.textColor(.blueLight)
}
.buttonStyle(TagButtonStyle(style: .default, isFocused: false, isSelected: false))
.buttonStyle(TagButtonStyle(isFocused: false, isSelected: false, removeAction: nil))
.previewDisplayName()
}

Expand Down
28 changes: 14 additions & 14 deletions Sources/OrbitStorybook/Detail/Items/StorybookTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ struct StorybookTag {

@ViewBuilder static var basic: some View {
VStack(alignment: .leading, spacing: .large) {
stack(style: .default, isFocused: true)
stack(style: .default, isFocused: false)
stack(style: .removable(action: {}), isFocused: true)
stack(style: .removable(action: {}), isFocused: false)
stack(isRemovable: false, isFocused: true)
stack(isRemovable: false, isFocused: false)
stack(isRemovable: true, isFocused: true)
stack(isRemovable: true, isFocused: false)
Separator()
stack(style: .default, isFocused: false, idealWidth: false)
stack(style: .removable(action: {}), isFocused: true, idealWidth: false)
stack(isRemovable: false, isFocused: false, idealWidth: false)
stack(isRemovable: true, isFocused: true, idealWidth: false)
Separator()
HStack(spacing: .medium) {
StateWrapper(true) { isSelected in
Tag(label, icon: .sort, style: .removable(action: {}), isSelected: isSelected)
Tag(label, icon: .sort, isSelected: isSelected, removeAction: {})
}
StateWrapper(false) { isSelected in
Tag(icon: .notificationAdd, isFocused: false, isSelected: isSelected)
Expand All @@ -27,23 +27,23 @@ struct StorybookTag {
.previewDisplayName()
}

@ViewBuilder static func stack(style: TagStyle, isFocused: Bool, idealWidth: Bool? = nil) -> some View {
static func stack(isRemovable: Bool, isFocused: Bool, idealWidth: Bool? = nil) -> some View {
HStack(spacing: .medium) {
VStack(spacing: .small) {
tag(style: style, isFocused: isFocused, isSelected: false)
tag(style: style, isFocused: isFocused, isSelected: true)
tag(isRemovable: isRemovable, isFocused: isFocused, isSelected: false)
tag(isRemovable: isRemovable, isFocused: isFocused, isSelected: true)
}
}
.idealSize(horizontal: idealWidth)
}

@ViewBuilder static func tag(style: TagStyle, isFocused: Bool, isSelected: Bool) -> some View {
StateWrapper((style, isSelected, true)) { state in
static func tag(isRemovable: Bool, isFocused: Bool, isSelected: Bool) -> some View {
StateWrapper((isRemovable, isSelected, true)) { state in
Tag(
label,
style: style == .default ? .default : .removable(action: { state.wrappedValue.2 = false }),
isFocused: isFocused,
isSelected: state.1
isSelected: state.1,
removeAction: state.0.wrappedValue ? { state.wrappedValue.2 = false } : nil
)
.opacity(state.wrappedValue.2 ? 1 : 0)
}
Expand Down

0 comments on commit ccb07a4

Please sign in to comment.