diff --git a/Sources/Orbit/Components/Badge.swift b/Sources/Orbit/Components/Badge.swift index 0d0094a6023..333c04b0592 100644 --- a/Sources/Orbit/Components/Badge.swift +++ b/Sources/Orbit/Components/Badge.swift @@ -6,7 +6,7 @@ import SwiftUI /// They can be updated when a status changes, but they should not be actionable. /// /// - Note: [Orbit definition](https://orbit.kiwi/components/badge/) -public struct Badge: View { +public struct Badge: View, PotentiallyEmptyView { @Environment(\.status) private var status @Environment(\.sizeCategory) private var sizeCategory diff --git a/Sources/Orbit/Components/BadgeList.swift b/Sources/Orbit/Components/BadgeList.swift index 873d1e2e1b8..a94ca280b15 100644 --- a/Sources/Orbit/Components/BadgeList.swift +++ b/Sources/Orbit/Components/BadgeList.swift @@ -5,7 +5,7 @@ import SwiftUI /// The items in the list should all be static information, *not* actionable. /// /// - Note: [Orbit definition](https://orbit.kiwi/components/information/badgelist/) -public struct BadgeList: View { +public struct BadgeList: View, PotentiallyEmptyView { @Environment(\.status) private var status @Environment(\.textAccentColor) private var textAccentColor diff --git a/Sources/Orbit/Components/Button.swift b/Sources/Orbit/Components/Button.swift index 257d710c8aa..e1c8719435d 100644 --- a/Sources/Orbit/Components/Button.swift +++ b/Sources/Orbit/Components/Button.swift @@ -4,7 +4,7 @@ import SwiftUI /// /// - Note: [Orbit definition](https://orbit.kiwi/components/button/) /// - Important: Component expands horizontally unless prevented by `fixedSize` or `idealSize` modifier. -public struct Button: View { +public struct Button: View, PotentiallyEmptyView { @Environment(\.suppressButtonStyle) private var suppressButtonStyle diff --git a/Sources/Orbit/Components/ButtonLink.swift b/Sources/Orbit/Components/ButtonLink.swift index 1f6f453268b..e7906744065 100644 --- a/Sources/Orbit/Components/ButtonLink.swift +++ b/Sources/Orbit/Components/ButtonLink.swift @@ -3,7 +3,7 @@ import SwiftUI /// Displays a single, less important action a user can take. /// /// - Note: [Orbit definition](https://orbit.kiwi/components/buttonlink/) -public struct ButtonLink: View { +public struct ButtonLink: View, PotentiallyEmptyView { @Environment(\.suppressButtonStyle) var suppressButtonStyle diff --git a/Sources/Orbit/Components/CountryFlag.swift b/Sources/Orbit/Components/CountryFlag.swift index 885df930694..b945581eff4 100644 --- a/Sources/Orbit/Components/CountryFlag.swift +++ b/Sources/Orbit/Components/CountryFlag.swift @@ -10,7 +10,7 @@ import SwiftUI /// ``` /// /// - Note: [Orbit definition](https://orbit.kiwi/components/countryflag/) -public struct CountryFlag: View { +public struct CountryFlag: View, PotentiallyEmptyView { @Environment(\.textSize) var textSize @Environment(\.iconSize) var iconSize @@ -51,6 +51,10 @@ public struct CountryFlag: View { var size: CGFloat { (iconSize ?? textSize.map(Icon.Size.fromTextSize(size:)) ?? Icon.Size.normal.value) * sizeCategory.ratio } + + var isEmpty: Bool { + countryCode == nil + } } // MARK: - Inits diff --git a/Sources/Orbit/Components/Icon.swift b/Sources/Orbit/Components/Icon.swift index dc7696eb5dc..e03d5472375 100644 --- a/Sources/Orbit/Components/Icon.swift +++ b/Sources/Orbit/Components/Icon.swift @@ -25,7 +25,7 @@ import SwiftUI /// ``` /// /// - Note: [Orbit definition](https://orbit.kiwi/components/icon/) -public struct Icon: View, TextBuildable { +public struct Icon: View, TextBuildable, PotentiallyEmptyView { /// Approximate size ratio between SF Symbol and Orbit icon symbol. public static let sfSymbolToOrbitSymbolSizeRatio: CGFloat = 0.75 diff --git a/Sources/Orbit/Components/ListChoice.swift b/Sources/Orbit/Components/ListChoice.swift index d9851c04227..7826c357878 100644 --- a/Sources/Orbit/Components/ListChoice.swift +++ b/Sources/Orbit/Components/ListChoice.swift @@ -4,7 +4,7 @@ import SwiftUI /// /// - Note: [Orbit definition](https://orbit.kiwi/components/listchoice/) /// - Important: Component expands horizontally unless prevented by `fixedSize` or `idealSize` modifier. -public struct ListChoice: View { +public struct ListChoice: View, PotentiallyEmptyView { public let verticalPadding: CGFloat = .small // = 45 height @ normal size @@ -148,7 +148,7 @@ public struct ListChoice: View { } var isEmpty: Bool { - isHeaderEmpty && header is EmptyView && content is EmptyView && disclosure == .none + isHeaderEmpty && header.isEmpty && content.isEmpty && disclosure == .none } var isHeaderEmpty: Bool { diff --git a/Sources/Orbit/Components/Select.swift b/Sources/Orbit/Components/Select.swift index 554375f0050..a28106d23b4 100644 --- a/Sources/Orbit/Components/Select.swift +++ b/Sources/Orbit/Components/Select.swift @@ -187,6 +187,7 @@ struct SelectPreviews: PreviewProvider { static var previews: some View { PreviewWrapper { standalone + customContent idealSize sizing styles @@ -197,6 +198,9 @@ struct SelectPreviews: PreviewProvider { static var standalone: some View { VStack(spacing: .medium) { + Select(InputFieldPreviews.label, value: InputFieldPreviews.value) { + // No action + } Select(InputFieldPreviews.label, prefix: .grid, value: InputFieldPreviews.value) { // No action } @@ -214,6 +218,43 @@ struct SelectPreviews: PreviewProvider { .previewDisplayName() } + static var customContent: some View { + VStack(spacing: .medium) { + Select(value: "Value with a very very very very very long value..") { + // No action + } prefix: { + EmptyView() + } suffix: { + EmptyView() + } + + Select(value: "Value with a very very very very very long value..") { + // No action + } prefix: { + CountryFlag("") + } suffix: { + CountryFlag("") + } + + // FIXME: conditional content EmptyView + StateWrapper(false) { state in + Select(value: "Value with a very very very very very long value..") { + state.wrappedValue.toggle() + } prefix: { + if state.wrappedValue { + CountryFlag("us") + } + } suffix: { + if state.wrappedValue { + CountryFlag("us") + } + } + } + } + .padding(.medium) + .previewDisplayName() + } + static var idealSize: some View { VStack(spacing: .medium) { Select("Ideal size", prefix: .grid, value: InputFieldPreviews.value, action: {}) diff --git a/Sources/Orbit/Components/Tag.swift b/Sources/Orbit/Components/Tag.swift index ffb6815dbc4..7417b5cc018 100644 --- a/Sources/Orbit/Components/Tag.swift +++ b/Sources/Orbit/Components/Tag.swift @@ -4,7 +4,7 @@ import SwiftUI /// /// - Note: [Orbit definition](https://orbit.kiwi/components/tag/) /// - Important: Component can expand horizontally by using `idealSize` modifier. -public struct Tag: View { +public struct Tag: View, PotentiallyEmptyView { @Environment(\.idealSize) private var idealSize @Environment(\.textColor) private var textColor diff --git a/Sources/Orbit/Components/Text.swift b/Sources/Orbit/Components/Text.swift index 5b352f4f4e8..f417301f1bd 100644 --- a/Sources/Orbit/Components/Text.swift +++ b/Sources/Orbit/Components/Text.swift @@ -7,7 +7,7 @@ import SwiftUI /// /// - Note: [Orbit definition](https://orbit.kiwi/components/text/) /// - Important: Component has fixed vertical size. When the content is empty, the component results in `EmptyView`. -public struct Text: View, FormattedTextBuildable { +public struct Text: View, FormattedTextBuildable, PotentiallyEmptyView { @Environment(\.multilineTextAlignment) private var multilineTextAlignment @Environment(\.lineSpacing) private var lineSpacing diff --git a/Sources/Orbit/Components/TileGroup.swift b/Sources/Orbit/Components/TileGroup.swift index a7850c5f73e..54696854e6f 100644 --- a/Sources/Orbit/Components/TileGroup.swift +++ b/Sources/Orbit/Components/TileGroup.swift @@ -19,7 +19,7 @@ import SwiftUI /// ``` /// /// - Note: [Orbit definition](https://orbit.kiwi/components/tilegroup/) -public struct TileGroup: View { +public struct TileGroup: View, PotentiallyEmptyView { @ViewBuilder let content: Content @@ -38,7 +38,7 @@ public struct TileGroup: View { } var isEmpty: Bool { - content is EmptyView + content.isEmpty } /// Creates Orbit TileGroup component as a wrapper for Tile content. diff --git a/Sources/Orbit/Components/Timeline.swift b/Sources/Orbit/Components/Timeline.swift index 44378b0a90f..5ac6abe5f59 100644 --- a/Sources/Orbit/Components/Timeline.swift +++ b/Sources/Orbit/Components/Timeline.swift @@ -6,7 +6,7 @@ import SwiftUI /// - ``TimelineItem`` /// /// - Note: [Orbit definition](https://orbit.kiwi/components/progress-indicators/timeline/) -public struct Timeline: View { +public struct Timeline: View, PotentiallyEmptyView { @Environment(\.sizeCategory) var sizeCategory @ViewBuilder let content: Content @@ -35,7 +35,7 @@ public struct Timeline: View { } var isEmpty: Bool { - content is EmptyView + content.isEmpty } func progressLineHeight( diff --git a/Sources/Orbit/Support/Forms/InputContent.swift b/Sources/Orbit/Support/Forms/InputContent.swift index da89f5a1fe8..14d811a4661 100644 --- a/Sources/Orbit/Support/Forms/InputContent.swift +++ b/Sources/Orbit/Support/Forms/InputContent.swift @@ -134,6 +134,14 @@ struct InputContentPreviews: PreviewProvider { // No action } } + + InputContent(state: .default) { + headerPlaceholder + } prefix: { + CountryFlag("") + } suffix: { + EmptyView() + } } .padding(.medium) .previewDisplayName() diff --git a/Sources/Orbit/Support/Layout/IsEmpty.swift b/Sources/Orbit/Support/Layout/IsEmpty.swift index d26b785121b..3830a82c0c7 100644 --- a/Sources/Orbit/Support/Layout/IsEmpty.swift +++ b/Sources/Orbit/Support/Layout/IsEmpty.swift @@ -3,6 +3,10 @@ import SwiftUI extension View { var isEmpty: Bool { - self is EmptyView || (self as? Orbit.Icon)?.isEmpty == true || (self as? Orbit.Text)?.isEmpty == true + switch self { + case let view as PotentiallyEmptyView: return view.isEmpty + case is EmptyView: return true + default: return false + } } } diff --git a/Sources/Orbit/Support/Layout/PotentiallyEmptyView.swift b/Sources/Orbit/Support/Layout/PotentiallyEmptyView.swift new file mode 100644 index 00000000000..e8f07aa7367 --- /dev/null +++ b/Sources/Orbit/Support/Layout/PotentiallyEmptyView.swift @@ -0,0 +1,5 @@ + +/// A type that represents views that can optionally result in `EmptyView`. +protocol PotentiallyEmptyView { + var isEmpty: Bool { get } +}