Skip to content

Commit

Permalink
Add showsSeparator modifier to configure separator visibility in co…
Browse files Browse the repository at this point in the history
…mpatible components
  • Loading branch information
PavelHolec committed Sep 2, 2024
1 parent e90a740 commit 5ee7ade
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 83 deletions.
3 changes: 2 additions & 1 deletion Sources/Orbit/Components/Card.swift
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,8 @@ struct CardPreviews: PreviewProvider {
ListChoice("ListChoice", action: {})
.backgroundStyle(.blueLight, active: .greenLight)
ListChoice("ListChoice", icon: .map, action: {})
ListChoice("ListChoice", description: "ListChoice description", icon: .airplane, showSeparator: false, action: {})
ListChoice("ListChoice", description: "ListChoice description", icon: .airplane, action: {})
.showsSeparator(false)
}
.cardLayout(.fill)
.backgroundStyle(.clear)
Expand Down
47 changes: 19 additions & 28 deletions Sources/Orbit/Components/Collapse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,20 @@ import SwiftUI
/// }
/// ```
///
/// Use ``showsSeparator(_:)`` to adjust separator visibility.
///
/// ```swift
/// Collapse("Details", isExpanded: $showDetails) {
/// content
/// }
/// .showsSeparator(false)
/// ```
///
/// - Note: [Orbit.kiwi documentation](https://orbit.kiwi/components/collapse/)
public struct Collapse<Title: View, Content: View>: View {

private let showSeparator: Bool

@Environment(\.showsSeparator) private var showsSeparator

private let isExpanded: OptionalBindingSource<Bool>
@ViewBuilder private let content: Content
@ViewBuilder private let title: Title
Expand Down Expand Up @@ -49,34 +59,30 @@ public struct Collapse<Title: View, Content: View>: View {
}

@ViewBuilder private var separator: some View {
if showSeparator {
if showsSeparator {
Separator()
}
}

/// Creates Orbit ``Collapse`` component with custom content.
public init(
isExpanded: Binding<Bool>,
showSeparator: Bool = true,
@ViewBuilder content: () -> Content,
@ViewBuilder title: () -> Title
) {
self.title = title()
self.content = content()
self.showSeparator = showSeparator
self.isExpanded = .binding(isExpanded)
}

/// Creates Orbit ``Collapse`` component with custom content.
public init(
isExpanded: Bool = false,
showSeparator: Bool = true,
@ViewBuilder content: () -> Content,
@ViewBuilder title: () -> Title
) {
self.title = title()
self.content = content()
self.showSeparator = showSeparator
self.isExpanded = .state(isExpanded)
}
}
Expand All @@ -89,13 +95,9 @@ public extension Collapse where Title == CollapseTitle {
init(
_ title: some StringProtocol = String(""),
isExpanded: Binding<Bool>,
showSeparator: Bool = true,
@ViewBuilder content: () -> Content
) {
self.init(
isExpanded: isExpanded,
showSeparator: showSeparator
) {
self.init(isExpanded: isExpanded) {
content()
} title: {
CollapseTitle(title: Text(title))
Expand All @@ -107,13 +109,9 @@ public extension Collapse where Title == CollapseTitle {
init(
_ title: some StringProtocol = String(""),
isExpanded: Bool = false,
showSeparator: Bool = true,
@ViewBuilder content: () -> Content
) {
self.init(
isExpanded: isExpanded,
showSeparator: showSeparator
) {
self.init(isExpanded: isExpanded) {
content()
} title: {
CollapseTitle(title: Text(title))
Expand All @@ -125,16 +123,12 @@ public extension Collapse where Title == CollapseTitle {
init(
_ title: LocalizedStringKey = "",
isExpanded: Binding<Bool>,
showSeparator: Bool = true,
tableName: String? = nil,
bundle: Bundle? = nil,
comment: StaticString? = nil,
@ViewBuilder content: () -> Content
) {
self.init(
isExpanded: isExpanded,
showSeparator: showSeparator
) {
self.init(isExpanded: isExpanded) {
content()
} title: {
CollapseTitle(title: Text(title, tableName: tableName, bundle: bundle))
Expand All @@ -146,16 +140,12 @@ public extension Collapse where Title == CollapseTitle {
init(
_ title: LocalizedStringKey = "",
isExpanded: Bool = false,
showSeparator: Bool = true,
tableName: String? = nil,
bundle: Bundle? = nil,
comment: StaticString? = nil,
@ViewBuilder content: () -> Content
) {
self.init(
isExpanded: isExpanded,
showSeparator: showSeparator
) {
self.init(isExpanded: isExpanded) {
content()
} title: {
CollapseTitle(title: Text(title, tableName: tableName, bundle: bundle))
Expand Down Expand Up @@ -244,9 +234,10 @@ struct CollapsePreviews: PreviewProvider {
} title: {
headerPlaceholder
}
Collapse("No separator", isExpanded: .constant(false), showSeparator: false) {
Collapse("No separator", isExpanded: .constant(false)) {
contentPlaceholder
}
.showsSeparator(false)
}
.padding(.medium)
.previewDisplayName()
Expand Down
40 changes: 24 additions & 16 deletions Sources/Orbit/Components/ListChoice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import SwiftUI
/// The title and icon colors can be modified by ``textColor(_:)`` and ``iconColor(_:)`` modifiers.
/// The icon size can be modified by ``iconSize(custom:)`` modifier.
///
/// The default background can be overridden by ``SwiftUI/View/backgroundStyle(_:)`` modifier.
/// The default background can be overridden by ``backgroundStyle(_:)`` modifier.
///
/// A ``Status`` can be modified by ``status(_:)`` modifier:
///
Expand All @@ -54,6 +54,23 @@ import SwiftUI
/// .status(.critical)
/// ```
///
/// A ListChoice shows a separator at the bottom by default.
/// Use ``showsSeparator(_:)`` to modify separator visibility for ListChoice components in a subview:
///
/// ```swift
/// VStack {
/// ListChoice("ListChoice with no separator") { /* No action */ }
/// .showsSeparator(false)
/// ListChoice("ListChoice with separator") { /* No action */ }
/// }
///
/// VStack {
/// ListChoice("ListChoice with no separator") { /* No action */ }
/// ListChoice("ListChoice with no separator") { /* No action */ }
/// }
/// .showsSeparator(false)
/// ```
///
/// Before the action is triggered, a haptic feedback is fired via ``HapticsProvider/sendHapticFeedback(_:)``.
///
/// ### Layout
Expand All @@ -69,9 +86,9 @@ public struct ListChoice<Icon: View, Title: View, Description: View, Header: Vie

@Environment(\.idealSize) private var idealSize
@Environment(\.isHapticsEnabled) private var isHapticsEnabled
@Environment(\.showsSeparator) private var showsSeparator

private let disclosure: ListChoiceDisclosure?
private let showSeparator: Bool
private let action: () -> Void
@ViewBuilder private let title: Title
@ViewBuilder private let description: Description
Expand Down Expand Up @@ -206,7 +223,7 @@ public struct ListChoice<Icon: View, Title: View, Description: View, Header: Vie
}

@ViewBuilder private var separator: some View {
if showSeparator {
if showsSeparator {
Separator()
}
}
Expand Down Expand Up @@ -235,7 +252,6 @@ public struct ListChoice<Icon: View, Title: View, Description: View, Header: Vie
/// Creates Orbit ``ListChoice`` component with custom content.
public init(
disclosure: ListChoiceDisclosure? = .disclosure(),
showSeparator: Bool = true,
action: @escaping () -> Void,
@ViewBuilder content: () -> Content = { EmptyView() },
@ViewBuilder title: () -> Title = { EmptyView() },
Expand All @@ -244,7 +260,6 @@ public struct ListChoice<Icon: View, Title: View, Description: View, Header: Vie
@ViewBuilder header: () -> Header = { EmptyView() }
) {
self.disclosure = disclosure
self.showSeparator = showSeparator
self.title = title()
self.description = description()
self.action = action
Expand All @@ -267,14 +282,10 @@ public extension ListChoice where Title == Text, Description == Text, Header ==
icon: Icon.Symbol? = nil,
value: some StringProtocol = String(""),
disclosure: ListChoiceDisclosure? = .disclosure(),
showSeparator: Bool = true,
action: @escaping () -> Void,
@ViewBuilder content: () -> Content = { EmptyView() }
) {
self.init(
disclosure: disclosure,
showSeparator: showSeparator
) {
self.init(disclosure: disclosure) {
action()
} content: {
content()
Expand All @@ -297,17 +308,13 @@ public extension ListChoice where Title == Text, Description == Text, Header ==
icon: Icon.Symbol? = nil,
value: some StringProtocol = String(""),
disclosure: ListChoiceDisclosure? = .disclosure(),
showSeparator: Bool = true,
tableName: String? = nil,
bundle: Bundle? = nil,
titleComment: StaticString? = nil,
action: @escaping () -> Void,
@ViewBuilder content: () -> Content = { EmptyView() }
) {
self.init(
disclosure: disclosure,
showSeparator: showSeparator
) {
self.init(disclosure: disclosure) {
action()
} content: {
content()
Expand Down Expand Up @@ -638,7 +645,8 @@ struct ListChoicePreviews: PreviewProvider {
Card {
ListChoice(title, disclosure: .none, action: {})
ListChoice(title, description: description, disclosure: .none, action: {})
ListChoice(title, description: "No Separator", disclosure: .none, showSeparator: false, action: {})
ListChoice(title, description: "No Separator", disclosure: .none, action: {})
.showsSeparator(false)
ListChoice(title, icon: .airplane, disclosure: .none, action: {})
ListChoice(title, icon: .airplane, disclosure: .none, action: {})
.iconColor(.blueNormal)
Expand Down
3 changes: 3 additions & 0 deletions Sources/Orbit/Components/SegmentedSwitch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public struct SegmentedSwitch<Selection: Hashable, Label: View, Content: View>:

@Environment(\.colorScheme) private var colorScheme
@Environment(\.idealSize) private var idealSize
@Environment(\.showsSeparator) private var showsSeparator

@Binding private var selection: Selection
private let message: Message?

Expand Down Expand Up @@ -158,6 +160,7 @@ public struct SegmentedSwitch<Selection: Hashable, Label: View, Content: View>:
.frame(width: borderWidth)
.frame(maxHeight: .infinity)
.padding(.vertical, borderWidth)
.opacity(showsSeparator ? 1 : 0)
}

private func unselectedPreferences(_ preferences: [IDPreference]) -> [(Int, IDPreference)] {
Expand Down
3 changes: 3 additions & 0 deletions Sources/Orbit/Components/Tabs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ public struct Tabs<Selection: Hashable, Content: View>: View {

@Environment(\.colorScheme) private var colorScheme
@Environment(\.idealSize) private var idealSize
@Environment(\.showsSeparator) private var showsSeparator
@Environment(\.sizeCategory) private var sizeCategory
@Environment(\.textColor) private var textColor

@Binding private var selection: Selection
@State private var activeTabStyles: [ActiveTabStyle] = []

Expand Down Expand Up @@ -146,6 +148,7 @@ public struct Tabs<Selection: Hashable, Content: View>: View {
.frame(width: .hairline)
.padding(.vertical, .xSmall)
.offset(x: separatorXOffset(index: index, preferences: preferences, geometry: geometry))
.opacity(showsSeparator ? 1 : 0)
}
}
}
Expand Down
29 changes: 12 additions & 17 deletions Sources/Orbit/Components/Tile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import SwiftUI
/// The title and icon colors can be modified by ``textColor(_:)`` and ``iconColor(_:)`` modifiers.
/// The icon size can be modified by ``iconSize(custom:)`` modifier.
///
/// The default background can be overridden by ``SwiftUI/View/backgroundStyle(_:)`` modifier.
/// The default background can be overridden by ``backgroundStyle(_:)`` modifier.
///
/// A ``Status`` can be modified by ``status(_:)`` modifier:
///
Expand All @@ -30,6 +30,15 @@ import SwiftUI
/// .status(.critical)
/// ```
///
/// Use ``showsSeparator(_:)`` to adjust separator visibility.
///
/// ```swift
/// Tile("Details") {
/// // Action
/// }
/// .showsSeparator(false)
/// ```
///
/// Before the action is triggered, a haptic feedback is fired via ``HapticsProvider/sendHapticFeedback(_:)``.
///
/// ### Layout
Expand All @@ -41,8 +50,8 @@ public struct Tile<Icon: View, Title: View, Description: View, Content: View>: V

@Environment(\.idealSize) private var idealSize
@Environment(\.isInsideTileGroup) private var isInsideTileGroup
@Environment(\.isTileSeparatorVisible) private var isTileSeparatorVisible
@Environment(\.isHapticsEnabled) private var isHapticsEnabled
@Environment(\.showsSeparator) private var showsSeparator

private let disclosure: TileDisclosure?
private let showBorder: Bool
Expand Down Expand Up @@ -156,7 +165,7 @@ public struct Tile<Icon: View, Title: View, Description: View, Content: View>: V
}

@ViewBuilder private var separator: some View {
if isInsideTileGroup, isTileSeparatorVisible {
if isInsideTileGroup, showsSeparator {
Separator()
}
}
Expand Down Expand Up @@ -250,20 +259,6 @@ public extension Tile where Title == Heading, Description == Text, Icon == Orbit
}
}

// MARK: - Modifiers
public extension Tile {

/// Sets the visibility of the separator associated with this tile.
///
/// Only applies if the tile is contained in a ``TileGroup``.
///
/// - Parameter isVisible: Whether the separator is visible or not.
func tileSeparator(_ isVisible: Bool) -> some View {
self
.environment(\.isTileSeparatorVisible, isVisible)
}
}

// MARK: - Types

public enum TileDisclosure: Equatable {
Expand Down
6 changes: 3 additions & 3 deletions Sources/Orbit/Components/TileGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import SwiftUI
/// ```
///
/// All tiles in a group include bottom separators by default, except for the last separator.
/// Use ``Tile/tileSeparator(_:)`` to modify separator visibility for a given tile:
/// Use ``showsSeparator(_:)`` to modify separator visibility for a given tile:
///
/// ```swift
/// TileGroup {
/// Tile("Tile with no Separator")
/// .tileSeparator(false)
/// .showsSeparator(false)
/// Tile("Tile 2")
/// }
/// ```
Expand Down Expand Up @@ -104,7 +104,7 @@ struct TileGroupPreviews: PreviewProvider {
}
Tile("Title", description: "No disclosure", icon: .notification, disclosure: .none, action: {})
Tile("No Separator", icon: .notification, action: {})
.tileSeparator(false)
.showsSeparator(false)
Tile("Title", description: TilePreviews.description, icon: .airplane, action: {})
}

Expand Down
3 changes: 2 additions & 1 deletion Sources/Orbit/Support/Components/TileBorder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ struct TileBorderModifierPreviews: PreviewProvider {
}
.status(.critical)

ListChoice("ListChoice", showSeparator: false, action: {})
ListChoice("ListChoice", action: {})
.showsSeparator(false)
.fixedSize()
.tileBorder()
}
Expand Down
Loading

0 comments on commit 5ee7ade

Please sign in to comment.