commit
0acfd29998
|
@ -1,3 +1,5 @@
|
||||||
# UIPreview
|
# UIPreview
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
[API documentation](https://github.com/0111b/UIPreview/wiki)
|
||||||
|
|
|
@ -3,6 +3,8 @@ import SwiftUI
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//xcrun simctl list devicetypes
|
//xcrun simctl list devicetypes
|
||||||
|
|
||||||
|
/// Default devices used in `View.previewAsScreen(deviceNames:)`
|
||||||
public let defaultDeviceNames: [String] =
|
public let defaultDeviceNames: [String] =
|
||||||
[
|
[
|
||||||
"iPhone 8",
|
"iPhone 8",
|
||||||
|
|
|
@ -4,6 +4,7 @@ import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
extension UICatalog {
|
extension UICatalog {
|
||||||
|
/// Generated preview instance
|
||||||
@available(iOS 14, *)
|
@available(iOS 14, *)
|
||||||
public struct Preview {
|
public struct Preview {
|
||||||
init(_ view: AnyView, title: String) {
|
init(_ view: AnyView, title: String) {
|
||||||
|
@ -18,6 +19,8 @@ extension UICatalog {
|
||||||
}.navigationBarTitle(title)
|
}.navigationBarTitle(title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert preview to the `UIViewController`
|
||||||
|
/// - Returns: generated UIViewController instance
|
||||||
public func asViewController() -> UIViewController {
|
public func asViewController() -> UIViewController {
|
||||||
preview().asViewController()
|
preview().asViewController()
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,13 @@ import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
extension UICatalog {
|
extension UICatalog {
|
||||||
|
/// Configuration which will be used for preview generation
|
||||||
public struct PreviewConfiguration {
|
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,
|
public init(themes: [Theme] = Theme.allCases,
|
||||||
contentSize: [UIContentSizeCategory] = [.unspecified],
|
contentSize: [UIContentSizeCategory] = [.unspecified],
|
||||||
size: CGSize? = nil) {
|
size: CGSize? = nil) {
|
||||||
|
@ -17,11 +23,15 @@ extension UICatalog {
|
||||||
let contentSize: [UIContentSizeCategory]
|
let contentSize: [UIContentSizeCategory]
|
||||||
let size: CGSize?
|
let size: CGSize?
|
||||||
|
|
||||||
|
/// Adjusts the size of the generated preview
|
||||||
|
/// - Parameter newSize: required size
|
||||||
|
/// - Returns: updated configuration
|
||||||
public func with(size newSize: CGSize) -> PreviewConfiguration {
|
public func with(size newSize: CGSize) -> PreviewConfiguration {
|
||||||
PreviewConfiguration(themes: themes, contentSize: contentSize, size: newSize)
|
PreviewConfiguration(themes: themes, contentSize: contentSize, size: newSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents color scheme
|
||||||
public enum Theme: CaseIterable {
|
public enum Theme: CaseIterable {
|
||||||
case light, dark
|
case light, dark
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,15 @@ import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
extension UICatalog {
|
extension UICatalog {
|
||||||
|
/// Describes the preview that will be generated
|
||||||
@available(iOS 14, *)
|
@available(iOS 14, *)
|
||||||
public struct PreviewDescriptor: Identifiable, Hashable {
|
public struct PreviewDescriptor: Identifiable, Hashable {
|
||||||
let builder: () -> AnyView
|
let builder: () -> AnyView
|
||||||
|
/// Unique identifier
|
||||||
public let id: String // swiftlint:disable:this identifier_name
|
public let id: String // swiftlint:disable:this identifier_name
|
||||||
|
/// Preview title
|
||||||
public let title: String
|
public let title: String
|
||||||
|
/// Returns generated preview
|
||||||
public var preview: Preview { Preview(builder(), title: title) }
|
public var preview: Preview { Preview(builder(), title: title) }
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
|
@ -24,6 +28,11 @@ extension UICatalog {
|
||||||
|
|
||||||
@available(iOS 14, *)
|
@available(iOS 14, *)
|
||||||
public extension UICatalog.PreviewDescriptor {
|
public extension UICatalog.PreviewDescriptor {
|
||||||
|
/// Creates the instance from suitable `UIView` subtype
|
||||||
|
/// - Parameters:
|
||||||
|
/// - content: reference to the type that can be converted to the preview
|
||||||
|
/// - configuration: preview configuration
|
||||||
|
/// - title: preview title
|
||||||
init<Content>(_ content: Content.Type,
|
init<Content>(_ content: Content.Type,
|
||||||
configuration: UICatalog.PreviewConfiguration = .init(),
|
configuration: UICatalog.PreviewConfiguration = .init(),
|
||||||
title: String? = nil) where Content: UIViewCatalogPresentable {
|
title: String? = nil) where Content: UIViewCatalogPresentable {
|
||||||
|
@ -32,11 +41,19 @@ public extension UICatalog.PreviewDescriptor {
|
||||||
builder = { AnyView(CatalogItem<Content>(configuration: configuration)) }
|
builder = { AnyView(CatalogItem<Content>(configuration: configuration)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Group multiple previews together
|
||||||
|
/// - Parameters:
|
||||||
|
/// - content: list of the previews
|
||||||
|
/// - title: preview title
|
||||||
init(_ content: UICatalog.PreviewDescriptor...,
|
init(_ content: UICatalog.PreviewDescriptor...,
|
||||||
title: String? = nil) {
|
title: String? = nil) {
|
||||||
self.init(content, title: title)
|
self.init(content, title: title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Group multiple previews together
|
||||||
|
/// - Parameters:
|
||||||
|
/// - content: list of the previews
|
||||||
|
/// - title: preview title
|
||||||
init(_ content: [UICatalog.PreviewDescriptor],
|
init(_ content: [UICatalog.PreviewDescriptor],
|
||||||
title: String? = nil) {
|
title: String? = nil) {
|
||||||
id = content.map(\.id).joined()
|
id = content.map(\.id).joined()
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
/// Global namespace for the catalog
|
||||||
public enum UICatalog {}
|
public enum UICatalog {}
|
||||||
|
|
|
@ -3,15 +3,22 @@ import SwiftUI
|
||||||
#endif
|
#endif
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
/// Item that can be presented in the UICatalog
|
||||||
public protocol UICatalogPresentable {
|
public protocol UICatalogPresentable {
|
||||||
associatedtype PreviewModel: Hashable
|
associatedtype PreviewModel: Hashable
|
||||||
|
|
||||||
|
/// Applies data to the instance
|
||||||
|
/// - Parameter previewModel: data used in the preview
|
||||||
func apply(previewModel: PreviewModel)
|
func apply(previewModel: PreviewModel)
|
||||||
|
|
||||||
|
/// List of different data configurations used in the preview
|
||||||
static var previewModels: [PreviewModel] { get }
|
static var previewModels: [PreviewModel] { get }
|
||||||
|
|
||||||
|
/// Generates new instance for the preview
|
||||||
static func makePreviewInstance() -> Self
|
static func makePreviewInstance() -> Self
|
||||||
|
|
||||||
|
/// Applies preview data
|
||||||
|
/// - Parameter model: preview data
|
||||||
@available(iOS 13, *)
|
@available(iOS 13, *)
|
||||||
func preview(with model: PreviewModel) -> AnyView
|
func preview(with model: PreviewModel) -> AnyView
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,15 @@ import SwiftUI
|
||||||
#endif
|
#endif
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
/// Generic helper to display `UIViewController` in the Swift UI
|
||||||
@available(iOS 13, *)
|
@available(iOS 13, *)
|
||||||
public struct UIViewControllerWrapper<ContentView: UIViewController>: UIViewControllerRepresentable {
|
public struct UIViewControllerWrapper<ContentView: UIViewController>: UIViewControllerRepresentable {
|
||||||
let contextBuilder: () -> ViewCoordinator<ContentView>
|
let contextBuilder: () -> ViewCoordinator<ContentView>
|
||||||
|
|
||||||
|
/// Make new instance with given parameters
|
||||||
|
/// - Parameters:
|
||||||
|
/// - builder: describes how to build content
|
||||||
|
/// - update: describes how to update content
|
||||||
public init(_ builder: @autoclosure @escaping () -> ContentView,
|
public init(_ builder: @autoclosure @escaping () -> ContentView,
|
||||||
update: @escaping (ContentView) -> Void = { _ in }) {
|
update: @escaping (ContentView) -> Void = { _ in }) {
|
||||||
contextBuilder = {
|
contextBuilder = {
|
||||||
|
|
|
@ -3,10 +3,15 @@ import SwiftUI
|
||||||
#endif
|
#endif
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
/// Generic helper to display `UIView` in the Swift UI
|
||||||
@available(iOS 13, *)
|
@available(iOS 13, *)
|
||||||
public struct UIViewWrapper<ContentView: UIView>: UIViewRepresentable {
|
public struct UIViewWrapper<ContentView: UIView>: UIViewRepresentable {
|
||||||
let contextBuilder: () -> ViewCoordinator<ContentView>
|
let contextBuilder: () -> ViewCoordinator<ContentView>
|
||||||
|
|
||||||
|
/// Make new instance with given parameters
|
||||||
|
/// - Parameters:
|
||||||
|
/// - builder: describes how to build content
|
||||||
|
/// - update: describes how to update content
|
||||||
public init(_ builder: @autoclosure @escaping () -> ContentView,
|
public init(_ builder: @autoclosure @escaping () -> ContentView,
|
||||||
update: @escaping (ContentView) -> Void = { _ in }) {
|
update: @escaping (ContentView) -> Void = { _ in }) {
|
||||||
contextBuilder = {
|
contextBuilder = {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/// Coordinates `UIView` and `UIViewController` updates
|
||||||
public final class ViewCoordinator<ContentView> {
|
public final class ViewCoordinator<ContentView> {
|
||||||
typealias Builder = () -> ContentView
|
typealias Builder = () -> ContentView
|
||||||
typealias Updater = (ContentView) -> Void
|
typealias Updater = (ContentView) -> Void
|
||||||
|
|
Loading…
Reference in New Issue