Extract preview body in the configuration
This commit is contained in:
parent
3a0051ca0c
commit
e3f915b2cb
|
@ -0,0 +1,8 @@
|
|||
import SwiftUI
|
||||
|
||||
@available(iOS 13, *)
|
||||
extension View {
|
||||
func eraseToAny() -> AnyView {
|
||||
AnyView(self)
|
||||
}
|
||||
}
|
|
@ -11,55 +11,16 @@ struct CatalogItem<Content: UICatalogPresentable>: View {
|
|||
ForEach(values: Content.previewModels) { model in
|
||||
ForEach(values: configuration.colorSchemes) { scheme in
|
||||
ForEach(values: configuration.contentSizeCategory) { category in
|
||||
item(model: model,
|
||||
scheme: scheme,
|
||||
category: category,
|
||||
size: configuration.size)
|
||||
configuration.itemStyle
|
||||
.body(content: Content.preview(with: model),
|
||||
configuration: .init(modelInfo: String(describing: model),
|
||||
scheme: scheme,
|
||||
category: category,
|
||||
size: configuration.size))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func item(model: Content.PreviewModel,
|
||||
scheme: ColorScheme,
|
||||
category: ContentSizeCategory,
|
||||
size: CGSize?) -> some View {
|
||||
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
HStack {
|
||||
Image(systemName: scheme.systemImageName)
|
||||
Image(systemName: category.systemImageName)
|
||||
Text(String(describing: model))
|
||||
.lineLimit(4)
|
||||
.frame(maxWidth: 300, alignment: .leading)
|
||||
}
|
||||
.padding()
|
||||
|
||||
Content.preview(with: model)
|
||||
.modifier(SizeModifier(size: size))
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.colorScheme(scheme)
|
||||
.environment(\.sizeCategory, category)
|
||||
}
|
||||
.background(Color(.systemGroupedBackground))
|
||||
.cornerRadius(6)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
private struct SizeModifier: ViewModifier {
|
||||
let size: CGSize?
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
guard let size = size else {
|
||||
return AnyView(content)
|
||||
}
|
||||
return AnyView(content.frame(width: size.width,
|
||||
height: size.height))
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
|
|
@ -6,31 +6,47 @@ import UIKit
|
|||
extension UICatalog {
|
||||
/// Configuration which will be used for preview generation
|
||||
public struct PreviewConfiguration {
|
||||
/// Creates new instance
|
||||
/// - Parameters:
|
||||
/// - themes: list of themes
|
||||
/// - contentSize: list of content sizes
|
||||
/// - size: required size
|
||||
public init(themes: [Theme] = Theme.allCases,
|
||||
contentSize: [UIContentSizeCategory] = [.unspecified],
|
||||
size: CGSize? = nil) {
|
||||
self.themes = themes
|
||||
self.contentSize = contentSize
|
||||
self.size = size
|
||||
}
|
||||
|
||||
let themes: [Theme]
|
||||
let contentSize: [UIContentSizeCategory]
|
||||
let size: CGSize?
|
||||
let itemStyle: PreviewItemStyle
|
||||
}
|
||||
}
|
||||
|
||||
/// Adjusts the size of the generated preview
|
||||
/// - Parameter newSize: required size
|
||||
/// - Returns: updated configuration
|
||||
public func with(size newSize: CGSize) -> PreviewConfiguration {
|
||||
PreviewConfiguration(themes: themes, contentSize: contentSize, size: newSize)
|
||||
}
|
||||
extension UICatalog.PreviewConfiguration {
|
||||
/// Creates new instance
|
||||
/// - Parameters:
|
||||
/// - themes: list of themes
|
||||
/// - contentSize: list of content sizes
|
||||
/// - size: required size
|
||||
public init(themes: [UICatalog.Theme] = UICatalog.Theme.allCases,
|
||||
contentSize: [UIContentSizeCategory] = [.unspecified],
|
||||
size: CGSize? = nil) {
|
||||
self.themes = themes
|
||||
self.contentSize = contentSize
|
||||
self.size = size
|
||||
itemStyle = UICatalog.DefaultPreviewItemStyle()
|
||||
}
|
||||
|
||||
/// Adjusts the size of the generated preview
|
||||
/// - Parameter newSize: required size
|
||||
/// - Returns: updated configuration
|
||||
public func with(size newSize: CGSize) -> UICatalog.PreviewConfiguration {
|
||||
UICatalog.PreviewConfiguration(themes: themes, contentSize: contentSize, size: newSize)
|
||||
}
|
||||
}
|
||||
|
||||
extension UICatalog.PreviewConfiguration {
|
||||
@available(iOS 13, *)
|
||||
public func with(itemStyle: PreviewItemStyle) -> UICatalog.PreviewConfiguration {
|
||||
UICatalog.PreviewConfiguration(themes: self.themes,
|
||||
contentSize: self.contentSize,
|
||||
size: self.size,
|
||||
itemStyle: self.itemStyle)
|
||||
}
|
||||
}
|
||||
|
||||
extension UICatalog {
|
||||
/// Represents color scheme
|
||||
public enum Theme: CaseIterable {
|
||||
case light, dark
|
||||
|
|
|
@ -38,7 +38,7 @@ public extension UICatalog.PreviewDescriptor {
|
|||
title: String? = nil) where Content: UIViewCatalogPresentable {
|
||||
id = "\(content)"
|
||||
self.title = title ?? "\(content)"
|
||||
builder = { AnyView(CatalogItem<Content>(configuration: configuration)) }
|
||||
builder = { CatalogItem<Content>(configuration: configuration).eraseToAny() }
|
||||
}
|
||||
|
||||
/// Group multiple previews together
|
||||
|
@ -59,6 +59,6 @@ public extension UICatalog.PreviewDescriptor {
|
|||
id = content.map(\.id).joined()
|
||||
self.title = title ?? content.map(\.title).joined(separator: " ")
|
||||
let items = content.map { GroupItem.Model(title: $0.title, content: $0.builder) }
|
||||
builder = { AnyView(GroupItem(items: items)) }
|
||||
builder = { GroupItem(items: items).eraseToAny() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
import SwiftUI
|
||||
|
||||
@available(iOS 13, *)
|
||||
public protocol PreviewItemStyle {
|
||||
/// Creates a view that represents single item of a preview.
|
||||
/// - Parameters:
|
||||
/// - content: preview content
|
||||
/// - configuration: the properties of the preview.
|
||||
func body(content: AnyView, configuration: Self.Configuration) -> AnyView
|
||||
|
||||
/// The properties of a preview.
|
||||
typealias Configuration = UICatalog.PreviewItemStyleConfiguration
|
||||
}
|
||||
|
||||
extension UICatalog {
|
||||
@available(iOS 13, *)
|
||||
public struct PreviewItemStyleConfiguration {
|
||||
public let modelInfo: String
|
||||
public let scheme: ColorScheme
|
||||
public let category: ContentSizeCategory
|
||||
public let size: CGSize?
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
struct DefaultPreviewItemStyle: PreviewItemStyle {
|
||||
func body(content: AnyView, configuration: Configuration) -> AnyView {
|
||||
UICatalog.DefaultPreviewItemStyleView(content: content,
|
||||
configuration: configuration)
|
||||
.eraseToAny()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
struct DefaultPreviewItemStyleView: View {
|
||||
let content: AnyView
|
||||
let configuration: PreviewItemStyleConfiguration
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center, spacing: 0) {
|
||||
HStack {
|
||||
Image(systemName: configuration.scheme.systemImageName)
|
||||
Image(systemName: configuration.category.systemImageName)
|
||||
Text(configuration.modelInfo)
|
||||
.lineLimit(4)
|
||||
.frame(maxWidth: 300, alignment: .leading)
|
||||
}
|
||||
.padding()
|
||||
|
||||
content
|
||||
.modifier(SizeModifier(size: configuration.size))
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
.background(Color(.systemBackground))
|
||||
.colorScheme(configuration.scheme)
|
||||
.environment(\.sizeCategory, configuration.category)
|
||||
}
|
||||
.background(Color(.systemGroupedBackground))
|
||||
.cornerRadius(6)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 13, *)
|
||||
private struct SizeModifier: ViewModifier {
|
||||
let size: CGSize?
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
guard let size = size else {
|
||||
return content.eraseToAny()
|
||||
}
|
||||
return content.frame(width: size.width,
|
||||
height: size.height)
|
||||
.eraseToAny()
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@available(iOS 13, *)
|
||||
struct DefaultPreviewItemStyle_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ScrollView(.vertical) {
|
||||
UICatalog.DefaultPreviewItemStyleView(content: content, configuration: light)
|
||||
UICatalog.DefaultPreviewItemStyleView(content: content, configuration: dark)
|
||||
}
|
||||
}
|
||||
|
||||
static var content: AnyView {
|
||||
Text("Hello").background(Color.red)
|
||||
.eraseToAny()
|
||||
}
|
||||
|
||||
static let light = UICatalog.PreviewItemStyleConfiguration(modelInfo: "Info", scheme: .light,
|
||||
category: .medium, size: nil)
|
||||
|
||||
static let dark = UICatalog.PreviewItemStyleConfiguration(modelInfo: "Info", scheme: .dark,
|
||||
category: .medium, size: nil)
|
||||
}
|
||||
#endif
|
|
@ -25,7 +25,7 @@ public protocol UICatalogPresentable {
|
|||
|
||||
@available(iOS 13, *)
|
||||
extension UICatalogPresentable {
|
||||
public static func preview(with model: PreviewModel) -> some View {
|
||||
public static func preview(with model: PreviewModel) -> AnyView {
|
||||
makePreviewInstance().preview(with: model)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue