Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Illustration sizing with single enum option. #36

Merged
merged 1 commit into from
Feb 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/Orbit/Components/Dialog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public struct Dialog: View {
public var body: some View {
VStack(alignment: .center, spacing: .medium) {
if let illustration = illustration {
Illustration(illustration, maxHeight: 120)
Illustration(illustration, size: .intrinsic(maxHeight: 120))
.padding(.top, .medium)
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Orbit/Components/EmptyState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public struct EmptyState: View {

public var body: some View {
VStack(spacing: .medium) {
Illustration(illustration, maxHeight: 120)
Illustration(illustration, size: .intrinsic(maxHeight: 120))
.padding(.top, .large)

texts
Expand Down
2 changes: 1 addition & 1 deletion Sources/Orbit/Components/Icon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public extension Icon {
.aspectRatio(contentMode: mode)
.frame(width: size.value, height: size.value)
case .illustration(let illlustration, let size):
Illustration(illlustration, maxWidth: size.value, maxHeight: size.value, alignment: nil)
Illustration(illlustration, size: .intrinsic(maxWidth: size.value, maxHeight: size.value))
case .none:
EmptyView()
}
Expand Down
158 changes: 74 additions & 84 deletions Sources/Orbit/Components/Illustration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,47 @@ import SwiftUI
/// - Important: The component expands horizontally to infinity if alignment is provided.
public struct Illustration: View {

public static let defaultWidth: CGFloat = 300

let name: String
let bundle: Bundle
let maxWidth: CGFloat?
let maxHeight: CGFloat?
let alignment: Alignment?
let size: Size

public var body: some View {
if name.isEmpty == false {
SwiftUI.Image(name, bundle: bundle)
.resizable()
.scaledToFit()
.aspectRatio(contentMode: .fit)
.frame(maxWidth: maxWidth, maxHeight: maxHeight)
.frame(maxWidth: wrapperMaxWidth, alignment: alignment ?? .center)
.fixedSize(horizontal: false, vertical: true)
.frame(maxWidth: wrapperMaxWidth, alignment: wrapperAlignment)
}
}

var wrapperMaxWidth: CGFloat? {
alignment == nil ? nil : .infinity
switch size {
case .expanding: return .infinity
case .intrinsic: return nil
}
}

var wrapperAlignment: Alignment {
switch size {
case .expanding(_, .leading): return .leading
case .expanding(_, .center): return .center
case .expanding(_, .trailing): return .trailing
default: return .center
}
}

var maxWidth: CGFloat? {
switch size {
case .expanding: return nil
case .intrinsic(let maxWidth, _): return maxWidth
}
}

var maxHeight: CGFloat? {
switch size {
case .expanding(let maxHeight, _), .intrinsic(_, let maxHeight): return maxHeight
}
}
}

Expand All @@ -40,41 +60,43 @@ public extension Illustration {
///
/// - Parameters:
/// - image: Orbit Illustration asset.
/// - maxWidth: Maximum width of the resizeable image content. Detaults to ``Illustration/defaultWidth``.
/// - maxHeight: Maximum height of the resizeable image content. Defaults to `nil`.
/// - alignment: If provided, expands horizontally to infinity and aligns the resulting resized image. Defaults to `.center`.
/// - size: Sizing behavior of image content.
init(
_ image: Image,
maxWidth: CGFloat? = Self.defaultWidth,
maxHeight: CGFloat? = nil,
alignment: Alignment? = .center
size: Size = .expanding()
) {
self.name = image.assetName
self.bundle = .current
self.maxWidth = maxWidth
self.maxHeight = maxHeight
self.alignment = alignment
self.size = size
}

/// Creates Orbit Illustration component for custom image resource.
///
/// - Parameters:
/// - name: Resource name. Empty value results in no illustration.
/// - maxWidth: Maximum width of the resizeable image content. Detaults to ``Illustration/defaultWidth``.
/// - maxHeight: Maximum height of the resizeable image content. Defaults to `nil`.
/// - alignment: If provided, expands horizontally to infinity and aligns the resulting resized image. Defaults to `.center`.
/// - bundle: The bundle to search for the image resource and localization.
/// - size: Sizing behavior of image content.
init(
_ name: String,
bundle: Bundle,
maxWidth: CGFloat? = Self.defaultWidth,
maxHeight: CGFloat? = nil,
alignment: Alignment? = .center
size: Size = .expanding()
) {
self.name = name
self.bundle = bundle
self.maxWidth = maxWidth
self.maxHeight = maxHeight
self.alignment = alignment
self.size = size
}
}

// MARK: - Types
public extension Illustration {

enum Size {
public static let defaultMaxHeight: CGFloat = 200

/// Scales illustration up to optional maxHeight and expand horizontally to infinity with specified alignment.
case expanding(maxHeight: CGFloat? = Self.defaultMaxHeight, alignment: HorizontalAlignment = .center)
/// Scales illustraton up to maxWidth and/or maxHeight.
case intrinsic(maxWidth: CGFloat? = nil, maxHeight: CGFloat? = nil)
}
}

Expand All @@ -84,6 +106,7 @@ struct IllustrationPreviews: PreviewProvider {
public static var previews: some View {
PreviewWrapper {
standalone
intrinsic
custom

snapshots
Expand All @@ -94,12 +117,23 @@ struct IllustrationPreviews: PreviewProvider {
.previewDisplayName("All illustrations")
}
}

static var standalone: some View {
Illustration(.womanWithPhone)
.previewLayout(.sizeThatFits)
}

static var intrinsic: some View {
HStack {
Illustration(.womanWithPhone, size: .intrinsic(maxHeight: 80))
.border(.blue)
Illustration(.time, size: .intrinsic(maxHeight: 40))
.border(.blue)
}
.previewLayout(.sizeThatFits)
}


static var custom: some View {
Illustration("WomanWithPhone", bundle: .current)
.previewLayout(.sizeThatFits)
Expand All @@ -121,7 +155,7 @@ struct IllustrationPreviews: PreviewProvider {
HStack {
VStack {
Text("Leading", size: .small)
Illustration(.womanWithPhone, alignment: .leading)
Illustration(.womanWithPhone, size: .expanding(alignment: .leading))
.border(Color.cloudDark)
}
}
Expand All @@ -130,95 +164,51 @@ struct IllustrationPreviews: PreviewProvider {
Card("Default size") {
HStack {
VStack {
Text("No alignment", size: .small)
Illustration(.womanWithPhone, alignment: nil)
Text("Intrinsic", size: .small)
Illustration(.womanWithPhone, size: .intrinsic())
.border(Color.cloudDark)
}
}
}

Card("MaxWidth = 40") {
HStack {
VStack(alignment: .leading) {
Text("Leading", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, alignment: .leading)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Center", size: .small)
Illustration(.womanWithPhone, maxWidth: 40)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("None", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, alignment: nil)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Trailing", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, alignment: .trailing)
.border(Color.cloudDark)
}
Illustration(.womanWithPhone, size: .intrinsic(maxWidth: 40))
.border(Color.cloudDark)
}
}

Card("MaxHeight = 30") {
HStack {
VStack(alignment: .leading) {
Text("Leading", size: .small)
Illustration(.womanWithPhone, maxWidth: nil, maxHeight: 30, alignment: .leading)
Illustration(.womanWithPhone, size: .expanding(maxHeight: 30, alignment: .leading))
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Center", size: .small)
Illustration(.womanWithPhone, maxWidth: nil, maxHeight: 30)
Illustration(.womanWithPhone, size: .expanding(maxHeight: 30))
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("None", size: .small)
Illustration(.womanWithPhone, maxWidth: nil, maxHeight: 30, alignment: nil)
Illustration(.womanWithPhone, size: .intrinsic(maxHeight: 30))
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Trailing", size: .small)
Illustration(.womanWithPhone, maxWidth: nil, maxHeight: 30, alignment: .trailing)
Illustration(.womanWithPhone, size: .expanding(maxHeight: 30, alignment: .trailing))
.border(Color.cloudDark)
}
}
}

Card("MaxWidth = 40, MaxHeight = 30") {
HStack {
VStack(alignment: .leading) {
Text("Leading", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, maxHeight: 30, alignment: .leading)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Center", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, maxHeight: 30)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("None", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, maxHeight: 30, alignment: nil)
.border(Color.cloudDark)
}

VStack(alignment: .leading) {
Text("Trailing", size: .small)
Illustration(.womanWithPhone, maxWidth: 40, maxHeight: 30, alignment: .trailing)
.border(Color.cloudDark)
}
}
Illustration(.womanWithPhone, size: .intrinsic(maxWidth: 40, maxHeight: 30))
.border(Color.cloudDark)
}
}
.padding(.vertical)
Expand All @@ -230,7 +220,7 @@ struct IllustrationPreviews: PreviewProvider {
VStack(spacing: .small) {
ForEach(Illustration.Image.allCases, id: \.self) { image in
Separator(image.assetName)
Illustration(image, maxHeight: 100, alignment: .center)
Illustration(image, size: .expanding(maxHeight: 60))
}
}
.padding(.horizontal)
Expand Down