Last active
October 19, 2023 20:46
-
-
Save mflknr/f25bb09e74085efb9b13b79715262130 to your computer and use it in GitHub Desktop.
Convenience extension for SwiftUI previews.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// PreviewExt.swift | |
// | |
// | |
// Created by Marius Felkner on 2021-11-15. | |
// | |
// The MIT License (MIT) | |
// | |
// Copyright (c) 2021 Marius Felkner (https://twitter.com/mflknr) | |
// | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
// | |
// *****WARNING***** | |
// SINCE THE INTRODUCTION OF MACROS AND THE NEW PREVIEW CONTEXT | |
// THIS BECAME HEAVILY OUTDATED. USE WITH CAUTION OR JUST AS INSPIRATION | |
// *****WARNING***** | |
import SwiftUI | |
extension View { | |
func withColorSchemes() -> some View { | |
_PreviewColorScheme(content: self) | |
} | |
@available(iOS 15.0, *) | |
func withInterfaceOrientations() -> some View { | |
_PreviewInterfaceOrientations(content: self) | |
} | |
func asComponent() -> some View { | |
_PreviewComponent(content: self) | |
} | |
func onDevices(devices: [PreviewDevices] = [.iPhone6s, .iPhone13ProMax]) -> some View { | |
_PreviewDevices(content: self, devices: devices) | |
} | |
@available(iOS 15.0, *) | |
func withDynamicTypeSizes() -> some View { | |
_PreviewSizeCategory(content: self) | |
} | |
} | |
// MARK: - Prievew Wrapper | |
struct _PreviewColorScheme<Content: View>: View { | |
// MARK: - Properties | |
var content: Content | |
// MARK: - Body | |
var body: some View { | |
Group { | |
self.content | |
.preferredColorScheme(.light) | |
self.content | |
.preferredColorScheme(.dark) | |
} | |
} | |
} | |
@available(iOS 15.0, *) | |
struct _PreviewInterfaceOrientations<Content: View>: View { | |
// MARK: - Properties | |
var content: Content | |
// MARK: - Body | |
var body: some View { | |
Group { | |
self.content | |
.previewInterfaceOrientation(.portrait) | |
self.content | |
.previewInterfaceOrientation(.landscapeRight) | |
} | |
} | |
} | |
struct _PreviewComponent<Content: View>: View { | |
// MARK: - Properties | |
var content: Content | |
// MARK: - Body | |
var body: some View { | |
Group { | |
self.content | |
.previewLayout(.sizeThatFits) | |
} | |
} | |
} | |
struct _PreviewDevices<Content: View>: View { | |
// MARK: - Properties | |
var content: Content | |
var devices: [PreviewDevices] | |
// MARK: - Body | |
var body: some View { | |
Group { | |
ForEach(devices, id: \.self) { device in | |
self.content | |
.previewDevice(PreviewDevice.init(rawValue: device.rawValue)) | |
.previewDisplayName(device.rawValue) | |
} | |
} | |
} | |
} | |
@available(iOS 15.0, *) | |
struct _PreviewSizeCategory<Content: View>: View { | |
// MARK: - Properties | |
var content: Content | |
private let dynamicTypeSizes: [DynamicTypeSize] = [ | |
DynamicTypeSize.allCases.first ?? DynamicTypeSize.xSmall, | |
DynamicTypeSize.allCases.last ?? DynamicTypeSize.accessibility5 | |
] | |
// MARK: - Body | |
var body: some View { | |
Group { | |
self.content | |
.previewDisplayName("Default") | |
ForEach(dynamicTypeSizes, id: \.self) { | |
self.content | |
.environment(\.dynamicTypeSize, $0) | |
.previewDisplayName("\($0)") | |
} | |
} | |
} | |
} | |
// MARK: - Preview Devices | iPhone and iPad devices from `xcrun simctl list devicetypes` on 2021-11-15 | |
enum PreviewDevices: String, Hashable { | |
case iPhone4s = "iPhone 4s" | |
case iPhone5 = "iPhone 5" | |
case iPhone5s = "iPhone 5s" | |
case iPhone6Plus = "iPhone 6 Plus" | |
case iPhone6 = "iPhone 6" | |
case iPhone6s = "iPhone 6s" | |
case iPhone6sPlus = "iPhone 6s Plus" | |
case iPhoneSE_1stGen = "iPhone SE (1st Gen)" | |
case iPhone7 = "iPhone 7" | |
case iPhone7Plus = "iPhone 7 Plus" | |
case iPhone8 = "iPhone 8" | |
case iPhone8Plus = "iPhone 8 Plus" | |
case iPhoneX = "iPhone X" | |
case iPhoneXs = "iPhone Xs" | |
case iPhoneXsMax = "iPhone Xs Max" | |
case iPhoneXʀ = "iPhone Xʀ" | |
case iPhone11 = "iPhone 11" | |
case iPhone11Pro = "iPhone 11 Pro" | |
case iPhone11ProMax = "iPhone 11 Pro Max" | |
case iPhoneS_2ndGen = "iPhone SE (2nd Gen)" | |
case iPhone12mini = "iPhone 12 mini" | |
case iPhone12 = "iPhone 12" | |
case iPhone12Pro = "iPhone 12 Pro" | |
case iPhone12ProMax = "iPhone 12 Pro Max" | |
case iPhone13Pro = "iPhone 13 Pro" | |
case iPhone13ProMax = "iPhone 13 Pro Max" | |
case iPhone13mini = "iPhone 13 mini" | |
case iPhone13 = "iPhone 13" | |
case iPad2 = "iPad 2" | |
case iPadRetina = "iPad Retina" | |
case iPadAir = "iPad Air" | |
case iPadmini2 = "iPad mini 2" | |
case iPadmini3 = "iPad mini 3" | |
case iPadmini4 = "iPad mini 4" | |
case iPadAir2 = "iPad Air 2" | |
case iPadPro_9_7 = "iPad Pro (9.7-inch)" | |
case iPadPro_12_9_1stGen = "iPad Pro (12.9-inch) (1st generation)" | |
case iPad_5thGen = "iPad (5th generation)" | |
case iPadPro_12_9_2ndGen = "iPad Pro (12.9-inch) (2nd generation)" | |
case iPadPro_10_5 = "iPad Pro (10.5-inch)" | |
case iPad_6thGen = "iPad (6th generation)" | |
case iPad_7thGen = "iPad (7th generation)" | |
case iPadPro_11_1stGen = "iPad Pro (11-inch) (1st generation)" | |
case iPadPro_12_9_3rdGen = "iPad Pro (12.9-inch) (3rd generation)" | |
case iPadPro_11_2ndGen = "iPad Pro (11-inch) (2nd generation)" | |
case iPadPro_12_9_4thGen = "iPad Pro (12.9-inch) (4th generation)" | |
case iPadmini_5thGen = "iPad mini (5th generation)" | |
case iPadAir_3rdGen = "iPad Air (3rd generation)" | |
case iPad_8thGen = "iPad (8th generation)" | |
case iPad_9thGen = "iPad (9th generation)" | |
case iPadAir_4thGen = "iPad Air (4th generation)" | |
case iPadPro_11_3rdGen = "iPad Pro (11-inch) (3rd generation)" | |
case iPadPro_12_9_5thGen = "iPad Pro (12.9-inch) (5th generation)" | |
case iPadmini_6thGen = "iPad mini (6th generation)" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment