SwiftUIBackports // Downgrade compatibility.

- This commit needs to be reverted once we drop support of macOS versions older than 10.15 Catalina.
This commit is contained in:
ShikiSuen 2022-10-01 17:04:55 +08:00
parent dd4680e891
commit 86f7f88abd
61 changed files with 284 additions and 1 deletions

View File

@ -7,7 +7,7 @@ let package = Package(
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6),
.macOS(.v10_15),
.macOS(.v10_11),
],
products: [
.library(

View File

@ -1,6 +1,7 @@
import ObjectiveC
import SwiftUI
@available(macOS 10.15, *)
/// Provides a convenient method for backporting API,
/// including types, functions, properties, property wrappers and more.
///
@ -32,6 +33,7 @@ public struct Backport<Wrapped> {
/// The underlying content this backport represents.
public let content: Wrapped
@available(macOS 10.15, *)
/// Initializes a new Backport for the specified content.
/// - Parameter content: The content (type) that's being backported
public init(_ content: Wrapped) {
@ -39,16 +41,19 @@ public struct Backport<Wrapped> {
}
}
@available(macOS 10.15, *)
extension View {
/// Wraps a SwiftUI `View` that can be extended to provide backport functionality.
public var backport: Backport<Self> { .init(self) }
}
@available(macOS 10.15, *)
extension NSObjectProtocol {
/// Wraps an `NSObject` that can be extended to provide backport functionality.
public var backport: Backport<Self> { .init(self) }
}
@available(macOS 10.15, *)
extension AnyTransition {
/// Wraps an `AnyTransition` that can be extended to provide backport functionality.
public static var backport: Backport<AnyTransition> {

View File

@ -4,15 +4,18 @@
import SwiftUI
@available(macOS 10.15, *)
/// A geometry reader that automatically sizes its height to 'fit' its content.
public struct FittingGeometryReader<Content>: View where Content: View {
@State private var height: CGFloat = 10 // must be non-zero
private var content: (GeometryProxy) -> Content
@available(macOS 10.15, *)
public init(@ViewBuilder content: @escaping (GeometryProxy) -> Content) {
self.content = content
}
@available(macOS 10.15, *)
public var body: some View {
GeometryReader { geo in
content(geo)
@ -26,6 +29,7 @@ public struct FittingGeometryReader<Content>: View where Content: View {
}
}
@available(macOS 10.15, *)
private struct SizePreferenceKey: PreferenceKey {
static var defaultValue: CGSize = .zero
static func reduce(value: inout CGSize, nextValue: () -> CGSize) {
@ -33,6 +37,7 @@ private struct SizePreferenceKey: PreferenceKey {
}
}
@available(macOS 10.15, *)
private struct SizeModifier: ViewModifier {
func body(content: Content) -> some View {
content.overlay(

View File

@ -4,11 +4,13 @@
import SwiftUI
@available(macOS 10.15, *)
/// A scrollview that behaves more similarly to a `VStack` when its content size is small enough.
public struct FittingScrollView<Content: View>: View {
private let content: Content
private let showsIndicators: Bool
@available(macOS 10.15, *)
/// A new scrollview
/// - Parameters:
/// - showsIndicators: If true, the scroll view will show indicators when necessary
@ -18,6 +20,7 @@ public struct FittingScrollView<Content: View>: View {
self.content = content()
}
@available(macOS 10.15, *)
public var body: some View {
GeometryReader { geo in
SwiftUI.ScrollView(showsIndicators: showsIndicators) {

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(tvOS, deprecated: 13)
@available(macOS, deprecated: 10.15)
@available(watchOS, deprecated: 6)
@ -24,6 +25,7 @@ extension View {
#endif
}
@available(macOS 10.15, *)
/// Provides fine-grained control over the dismissal.
/// - Parameters:
/// - isModal: If `true`, the user will not be able to interactively dismiss

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension EnvironmentValues {
fileprivate func containsValue(forKey key: String) -> Bool {
value(forKey: key) != nil
@ -95,6 +96,7 @@ extension EnvironmentValues {
}
}
@available(macOS 10.15, *)
@propertyWrapper
internal struct StringlyTypedEnvironment<Value> {
final class Store<Value>: ObservableObject {
@ -116,12 +118,14 @@ internal struct StringlyTypedEnvironment<Value> {
}
}
@available(macOS 10.15, *)
extension StringlyTypedEnvironment: DynamicProperty {
func update() {
wrappedValue = env.value(forKey: key, as: Value.self)
}
}
@available(macOS 10.15, *)
@propertyWrapper
internal struct EnvironmentContains: DynamicProperty {
final class Store: ObservableObject {

View File

@ -13,6 +13,7 @@ import SwiftUI
*/
#if DEBUG
@available(macOS 10.15, *)
extension EnvironmentValues: CustomDebugStringConvertible {
public var debugDescription: String {
"\(self)"
@ -22,6 +23,7 @@ import SwiftUI
}
}
@available(macOS 10.15, *)
struct EnvironmentOutputModifier: ViewModifier {
@Environment(\.self) private var environment
@ -33,6 +35,7 @@ import SwiftUI
}
}
@available(macOS 10.15, *)
extension View {
func printEnvironment() -> some View {
modifier(EnvironmentOutputModifier())

View File

@ -82,6 +82,7 @@ import SwiftUI
}
}
@available(macOS 10.15, *)
extension View {
private func inject<Wrapped>(_ content: Wrapped) -> some View where Wrapped: View {
overlay(content.frame(width: 0, height: 0))
@ -94,6 +95,7 @@ import SwiftUI
}
}
@available(macOS 10.15, *)
private struct InspectionView<ViewType: PlatformView>: View {
let selector: (Inspector) -> ViewType?
let customize: (ViewType) -> Void
@ -145,6 +147,7 @@ import SwiftUI
}
#elseif os(macOS)
@available(macOS 10.15, *)
extension InspectionView {
fileprivate struct Representable: NSViewRepresentable {
let parent: InspectionView

View File

@ -23,6 +23,7 @@
#if os(macOS)
import AppKit
@available(macOS 10.15, *)
extension NSView {
public var parentController: NSViewController? {
var responder: NSResponder? = self

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@available(watchOS, deprecated: 7)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// A property wrapper type that reflects a value from `Store` and
/// invalidates a view on a change in value in that store.
@ -41,6 +42,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension Backport.AppStorage {
/// Creates a property that can read and write to a boolean user default.
///
@ -154,6 +156,7 @@ extension Backport.AppStorage {
}
}
@available(macOS 10.15, *)
extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiteral {
/// Creates a property that can read and write an Optional boolean user
/// default.
@ -270,6 +273,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: ExpressibleByNilLiter
}
}
@available(macOS 10.15, *)
extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
/// Creates a property that can read and write to a string user default,
/// transforming that to `RawRepresentable` data type.
@ -332,6 +336,7 @@ extension Backport.AppStorage where Wrapped == Any, Value: RawRepresentable {
}
}
@available(macOS 10.15, *)
private final class RefStorage<Value>: NSObject, ObservableObject {
@Published
fileprivate var value: Value

View File

@ -5,6 +5,7 @@
import SwiftUI
@available(iOS, deprecated: 15.0)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// Loads and displays an image from the specified URL.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Layers the views that you specify behind this view.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension EnvironmentValues {
/// An action that dismisses the current presentation.
///
@ -76,6 +77,7 @@ extension EnvironmentValues {
.init(presentation: presentationMode)
}
@available(macOS 10.15, *)
/// A Boolean value that indicates whether the view associated with this
/// environment is currently presented.
///
@ -107,6 +109,7 @@ extension EnvironmentValues {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 15)
@available(macOS, deprecated: 12)
@available(tvOS, deprecated: 15)

View File

@ -4,10 +4,12 @@
import SwiftUI
@available(macOS 10.15, *)
private struct BackportDynamicTypeKey: EnvironmentKey {
static var defaultValue: Backport.DynamicTypeSize = .large
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 15)
@available(tvOS, deprecated: 15)
@available(macOS, deprecated: 12)
@ -43,12 +45,14 @@ extension EnvironmentValues {
}
}
@available(macOS 10.15, *)
private struct DynamicTypeRangeKey: EnvironmentKey {
static var defaultValue: Range<Backport<Any>.DynamicTypeSize> {
.init(uncheckedBounds: (lower: .xSmall, upper: .accessibility5))
}
}
@available(macOS 10.15, *)
extension EnvironmentValues {
var dynamicTypeRange: Range<Backport<Any>.DynamicTypeSize> {
get { self[DynamicTypeRangeKey.self] }

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Sets the Dynamic Type size within the view to the given value.
///
@ -34,6 +35,7 @@ extension Backport where Wrapped: View {
content.environment(\.backportDynamicTypeSize, size)
}
@available(macOS 10.15, *)
/// Limits the Dynamic Type size within the view to the given range.
///
/// As an example, you can constrain the maximum Dynamic Type size in
@ -93,10 +95,12 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
private struct DynamicTypeRangeModifier: ViewModifier {
@Environment(\.dynamicTypeRange) private var range
@Environment(\.backportDynamicTypeSize) private var size
@available(macOS 10.15, *)
private var resolvedSize: Backport<Any>.DynamicTypeSize {
print(range)
return range.contains(size)
@ -104,6 +108,7 @@ private struct DynamicTypeRangeModifier: ViewModifier {
: max(range.lowerBound, min(range.upperBound, size))
}
@available(macOS 10.15, *)
func body(content: Content) -> some View {
content.environment(\.backportDynamicTypeSize, resolvedSize)
}

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(tvOS, deprecated: 15)
@available(macOS, deprecated: 12)
@available(watchOS, deprecated: 8)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// A Dynamic Type size, which specifies how large scalable content should be.
///

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@available(watchOS, deprecated: 7)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// A standard label for user interface items, consisting of an icon with a
/// title.
@ -109,6 +110,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
/// Creates a label with an icon image and a title generated from a
/// localized string.
@ -153,6 +155,7 @@ extension Backport.Label where Wrapped == Any, Title == Text, Icon == Image {
}
}
@available(macOS 10.15, *)
extension Backport.Label
where Wrapped == Any, Title == Backport.LabelStyleConfiguration.Title, Icon == Backport.LabelStyleConfiguration.Icon {
/// Creates a label representing the configuration of a style.

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -20,6 +21,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// A type-erased icon view of a label.
public struct Icon: View {
let content: AnyView
@ -29,14 +31,18 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// A description of the labeled item.
public internal(set) var title: LabelStyleConfiguration.Title
@available(macOS 10.15, *)
/// A symbolic representation of the labeled item.
public internal(set) var icon: LabelStyleConfiguration.Icon
@available(macOS 10.15, *)
internal var environment: EnvironmentValues = .init()
@available(macOS 10.15, *)
func environment(_ values: EnvironmentValues) -> Self {
var config = self
config.environment = values

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -19,6 +20,7 @@ public protocol BackportLabelStyle {
/// A view that represents the body of a label.
associatedtype Body: View
@available(macOS 10.15, *)
/// Creates a view that represents the body of a label.
///
/// The system calls this method for each ``Label`` instance in a view
@ -28,6 +30,7 @@ public protocol BackportLabelStyle {
@ViewBuilder func makeBody(configuration: Configuration) -> Body
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -38,24 +41,29 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
internal struct AnyLabelStyle: BackportLabelStyle {
let _makeBody: (Backport<Any>.LabelStyleConfiguration) -> AnyView
@available(macOS 10.15, *)
init<S: BackportLabelStyle>(_ style: S) {
_makeBody = { config in
AnyView(style.makeBody(configuration: config))
}
}
@available(macOS 10.15, *)
func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
@available(macOS 10.15, *)
private struct BackportLabelStyleEnvironmentKey: EnvironmentKey {
static var defaultValue: AnyLabelStyle?
}
@available(macOS 10.15, *)
extension EnvironmentValues {
var backportLabelStyle: AnyLabelStyle? {
get { self[BackportLabelStyleEnvironmentKey.self] }

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -15,6 +16,7 @@ extension Backport where Wrapped == Any {
public struct DefaultLabelStyle: BackportLabelStyle {
public init() {}
@available(macOS 10.15, *)
/// Creates a view that represents the body of a label.
///
/// The system calls this method for each ``Label`` instance in a view
@ -30,6 +32,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -16,6 +17,7 @@ extension Backport where Wrapped == Any {
/// Creates an icon-only label style.
public init() {}
@available(macOS 10.15, *)
/// Creates a view that represents the body of a label.
///
/// The system calls this method for each ``Label`` instance in a view
@ -28,6 +30,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -18,6 +19,7 @@ extension Backport where Wrapped == Any {
/// using a system-standard layout.
public init() {}
@available(macOS 10.15, *)
/// Creates a view that represents the body of a label.
///
/// The system calls this method for each ``Label`` instance in a view
@ -33,6 +35,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@ -16,6 +17,7 @@ extension Backport where Wrapped == Any {
/// Creates a title-only label style.
public init() {}
@available(macOS 10.15, *)
/// Creates a view that represents the body of a label.
///
/// The system calls this method for each ``Label`` instance in a view
@ -28,6 +30,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -135,6 +136,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension Backport.LabeledContent
where
Wrapped == Any, Label == Backport<Any>.LabeledContentStyleConfiguration.Label,
@ -164,6 +166,7 @@ where
}
}
@available(macOS 10.15, *)
extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content: View {
/// Creates a labeled view that generates its label from a localized string
/// key.
@ -183,6 +186,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content:
)
}
@available(macOS 10.15, *)
/// Creates a labeled view that generates its label from a string.
///
/// This initializer creates a ``Text`` label on your behalf, and treats the
@ -200,6 +204,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content:
}
}
@available(macOS 10.15, *)
extension Backport.LabeledContent: View where Wrapped == Any, Label: View, Content: View {
/// Creates a labeled view that generates its label from a localized string
/// key.
@ -220,6 +225,7 @@ extension Backport.LabeledContent: View where Wrapped == Any, Label: View, Conte
}
}
@available(macOS 10.15, *)
extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content == Text {
/// Creates a labeled informational view.
///
@ -244,6 +250,7 @@ extension Backport.LabeledContent where Wrapped == Any, Label == Text, Content =
)
}
@available(macOS 10.15, *)
/// Creates a labeled informational view.
///
/// This initializer creates a ``Text`` label on your behalf, and treats the

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -15,6 +16,7 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -25,25 +27,30 @@ public protocol BackportLabeledContentStyle {
@ViewBuilder func makeBody(configuration: Configuration) -> Body
}
@available(macOS 10.15, *)
internal struct AnyLabeledContentStyle: BackportLabeledContentStyle {
typealias Configuration = Backport<Any>.LabeledContentStyleConfiguration
let _makeBody: (Configuration) -> AnyView
@available(macOS 10.15, *)
init<S: BackportLabeledContentStyle>(_ style: S) {
_makeBody = { config in
AnyView(style.makeBody(configuration: config))
}
}
@available(macOS 10.15, *)
func makeBody(configuration: Configuration) -> some View {
_makeBody(configuration)
}
}
@available(macOS 10.15, *)
private struct BackportLabeledContentStyleEnvironmentKey: EnvironmentKey {
static var defaultValue: AnyLabeledContentStyle = .init(.automatic)
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -23,11 +24,13 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
init<V: View>(_ view: V) {
self.view = .init(view)
}
}
@available(macOS 10.15, *)
/// A type-erased content of a labeled content instance.
public struct Content: View {
@EnvironmentContains(key: "LabelsHiddenKey") private var isHidden
@ -38,22 +41,27 @@ extension Backport where Wrapped == Any {
.frame(maxWidth: .infinity, alignment: isHidden ? .leading : .trailing)
}
@available(macOS 10.15, *)
init<V: View>(_ view: V) {
self.view = .init(view)
}
}
@available(macOS 10.15, *)
/// The label of the labeled content instance.
public let label: Label
@available(macOS 10.15, *)
/// The content of the labeled content instance.
public let content: Content
@available(macOS 10.15, *)
internal init<L: View, C: View>(label: L, content: C) {
self.label = .init(label)
self.content = .init(content)
}
@available(macOS 10.15, *)
internal init<L: View, C: View>(@ViewBuilder content: () -> C, @ViewBuilder label: () -> L) {
self.content = .init(content())
self.label = .init(label())

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
public struct AutomaticLabeledContentStyle: BackportLabeledContentStyle {
public func makeBody(configuration: Configuration) -> some View {
@ -17,6 +18,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension BackportLabeledContentStyle where Self == Backport<Any>.AutomaticLabeledContentStyle {
static var automatic: Self { .init() }
}

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(watchOS, deprecated: 9)
@ -52,6 +53,7 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(watchOS, deprecated: 9)
@ -60,11 +62,13 @@ extension Backport where Wrapped == Any {
public struct NavigationLink<Label, Destination>: View where Label: View, Destination: View {
@Environment(\.navigationDestinations) private var destinations
@available(macOS 10.15, *)
private let valueType: AnyMetaType
private let value: Any?
private let label: Label
private let destination: () -> Destination
@available(macOS 10.15, *)
public init<P>(value: P?, @ViewBuilder label: () -> Label) where Destination == Never {
self.value = value
valueType = .init(type: P.self)
@ -72,6 +76,7 @@ extension Backport where Wrapped == Any {
self.label = label()
}
@available(macOS 10.15, *)
public var body: some View {
SwiftUI.NavigationLink {
if let value = value {
@ -85,10 +90,12 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
private struct NavigationDestinationsEnvironmentKey: EnvironmentKey {
static var defaultValue: [AnyMetaType: DestinationView] = [:]
}
@available(macOS 10.15, *)
extension EnvironmentValues {
fileprivate var navigationDestinations: [AnyMetaType: DestinationView] {
get { self[NavigationDestinationsEnvironmentKey.self] }
@ -100,22 +107,26 @@ extension EnvironmentValues {
}
}
@available(macOS 10.15, *)
private struct AnyMetaType {
let type: Any.Type
}
@available(macOS 10.15, *)
extension AnyMetaType: Equatable {
static func == (lhs: Self, rhs: Self) -> Bool {
lhs.type == rhs.type
}
}
@available(macOS 10.15, *)
extension AnyMetaType: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(ObjectIdentifier(type))
}
}
@available(macOS 10.15, *)
extension Dictionary {
fileprivate subscript(_ key: Any.Type) -> Value? where Key == AnyMetaType {
get { self[.init(type: key)] }
@ -123,6 +134,7 @@ extension Dictionary {
}
}
@available(macOS 10.15, *)
private struct DestinationView: View {
let content: (Any) -> AnyView
var body: Never { fatalError() }

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(watchOS, deprecated: 7)
@available(tvOS, deprecated: 14)
@ -21,6 +22,7 @@ extension Backport where Wrapped: View {
#endif
}
@available(macOS 10.15, *)
@ViewBuilder
public func navigationTitle(_ titleKey: LocalizedStringKey) -> some View {
#if os(macOS)

View File

@ -1,6 +1,7 @@
import Combine
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14.0)
@available(macOS, deprecated: 11.0)
@available(tvOS, deprecated: 14.0)
@ -27,18 +28,22 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
private struct ChangeModifier<Value: Equatable>: ViewModifier {
let value: Value
let action: (Value) -> Void
@available(macOS 10.15, *)
@State var oldValue: Value?
@available(macOS 10.15, *)
init(value: Value, action: @escaping (Value) -> Void) {
self.value = value
self.action = action
_oldValue = .init(initialValue: value)
}
@available(macOS 10.15, *)
func body(content: Content) -> some View {
content
.onReceive(Just(value)) { newValue in

View File

@ -8,10 +8,12 @@ import SwiftUI
import WatchKit
#endif
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(tvOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(watchOS, deprecated: 7)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// An action that opens a URL.
///
@ -83,6 +85,7 @@ extension Backport where Wrapped == Any {
case discarded
case systemAction(_ url: URL?)
@available(macOS 10.15, *)
var accepted: Bool {
if case .discarded = self {
return false
@ -92,31 +95,38 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
let value: Value
@available(macOS 10.15, *)
public static var handled: Result { .init(value: .handled) }
public static var discarded: Result { .init(value: .discarded) }
public static var systemAction: Result { .init(value: .systemAction(nil)) }
public static func systemAction(_ url: URL) -> Result { .init(value: .systemAction(url)) }
}
@available(macOS 10.15, *)
let handler: (URL) -> Result
@available(macOS 10.15, *)
public init(handler: @escaping (URL) -> Result) {
self.handler = handler
}
@available(macOS 10.15, *)
@available(watchOS, unavailable)
public func callAsFunction(_ url: URL) {
handleUrl(url)
}
@available(macOS 10.15, *)
@available(watchOS, unavailable)
public func callAsFunction(_ url: URL, completion: @escaping (_ accepted: Bool) -> Void) {
let result = handleUrl(url)
completion(result.accepted)
}
@available(macOS 10.15, *)
@discardableResult
private func handleUrl(_ url: URL) -> Result.Value {
let result = handler(url).value
@ -139,6 +149,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
private struct BackportOpenURLKey: EnvironmentKey {
static var defaultValue: Backport<Any>.OpenURLAction {
.init { url in
@ -157,6 +168,7 @@ private struct BackportOpenURLKey: EnvironmentKey {
}
}
@available(macOS 10.15, *)
extension EnvironmentValues {
public var backportOpenURL: Backport<Any>.OpenURLAction {
get { self[BackportOpenURLKey.self] }

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Layers the views that you specify in front of this view.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -13,6 +14,7 @@ extension Backport where Wrapped == Any {
@Environment(\.backportProgressViewStyle) private var style
let config: Backport<Any>.ProgressViewStyleConfiguration
@available(macOS 10.15, *)
public var body: some View {
Group {
if let style = style {
@ -25,6 +27,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -36,6 +39,7 @@ extension Backport.ProgressView where Wrapped == Any, CurrentValueLabel == Empty
self.init(config: .init(fractionCompleted: nil, preferredKind: .circular))
}
@available(macOS 10.15, *)
/// Creates a progress view for showing indeterminate progress that displays
/// a custom label.
///
@ -46,6 +50,7 @@ extension Backport.ProgressView where Wrapped == Any, CurrentValueLabel == Empty
config = .init(fractionCompleted: nil, label: .init(content: label()), preferredKind: .circular)
}
@available(macOS 10.15, *)
/// Creates a progress view for showing indeterminate progress that
/// generates its label from a localized string.
///
@ -62,6 +67,7 @@ extension Backport.ProgressView where Wrapped == Any, CurrentValueLabel == Empty
config = .init(fractionCompleted: nil, label: .init(content: Text(titleKey)), preferredKind: .circular)
}
@available(macOS 10.15, *)
/// Creates a progress view for showing indeterminate progress that
/// generates its label from a string.
///
@ -78,6 +84,7 @@ extension Backport.ProgressView where Wrapped == Any, CurrentValueLabel == Empty
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -105,6 +112,7 @@ extension Backport.ProgressView where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// Creates a progress view for showing determinate progress, with a
/// custom label.
///
@ -132,6 +140,7 @@ extension Backport.ProgressView where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// Creates a progress view for showing determinate progress, with a
/// custom label.
///
@ -166,6 +175,7 @@ extension Backport.ProgressView where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// Creates a progress view for showing determinate progress that generates
/// its label from a localized string.
///
@ -203,6 +213,7 @@ extension Backport.ProgressView where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// Creates a progress view for showing determinate progress that generates
/// its label from a string.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -16,6 +17,7 @@ extension Backport where Wrapped == Any {
case linear
}
@available(macOS 10.15, *)
/// A type-erased label describing the task represented by the progress
/// view.
public struct Label: View {
@ -26,6 +28,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// A type-erased label that describes the current value of a progress view.
public struct CurrentValueLabel: View {
let content: AnyView
@ -35,11 +38,13 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
/// The completed fraction of the task represented by the progress view,
/// from `0.0` (not yet started) to `1.0` (fully complete), or `nil` if the
/// progress is indeterminate or relative to a date interval.
public let fractionCompleted: Double?
@available(macOS 10.15, *)
/// A view that describes the task represented by the progress view.
///
/// If `nil`, then the task is self-evident from the surrounding context,
@ -49,6 +54,7 @@ extension Backport where Wrapped == Any {
/// label is equivalent to its `localizedDescription`.
public var label: Label?
@available(macOS 10.15, *)
/// A view that describes the current value of a progress view.
///
/// If `nil`, then the value of the progress view is either self-evident
@ -59,6 +65,7 @@ extension Backport where Wrapped == Any {
/// label is equivalent to its `localizedAdditionalDescription`.
public var currentValueLabel: CurrentValueLabel?
@available(macOS 10.15, *)
internal let preferredKind: Kind
internal var min: Double = 0
internal var max: Double = 1

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@available(watchOS, deprecated: 7.0)
@available(macOS 10.15, *)
/// A type that applies standard interaction behavior to all progress views
/// within a view hierarchy.
///
@ -37,12 +38,14 @@ public protocol BackportProgressViewStyle {
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@available(watchOS, deprecated: 7.0)
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
public func progressViewStyle<S: BackportProgressViewStyle>(_ style: S) -> some View {
content.environment(\.backportProgressViewStyle, .init(style))
}
}
@available(macOS 10.15, *)
internal struct AnyProgressViewStyle: BackportProgressViewStyle {
let _makeBody: (Backport<Any>.ProgressViewStyleConfiguration) -> AnyView
@ -57,10 +60,12 @@ internal struct AnyProgressViewStyle: BackportProgressViewStyle {
}
}
@available(macOS 10.15, *)
private struct BackportProgressViewStyleEnvironmentKey: EnvironmentKey {
static var defaultValue: AnyProgressViewStyle?
}
@available(macOS 10.15, *)
extension EnvironmentValues {
var backportProgressViewStyle: AnyProgressViewStyle? {
get { self[BackportProgressViewStyleEnvironmentKey.self] }

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -16,6 +17,7 @@ extension Backport where Wrapped == Any {
/// Creates a circular progress view style.
public init() {}
@available(macOS 10.15, *)
/// Creates a view representing the body of a progress view.
///
/// - Parameter configuration: The properties of the progress view being
@ -39,18 +41,22 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.CircularProgressViewStyle {
public static var circular: Self { .init() }
}
#if os(macOS)
@available(macOS 10.15, *)
private struct CircularRepresentable: NSViewRepresentable {
let configuration: Backport<Any>.ProgressViewStyleConfiguration
@available(macOS 10.15, *)
func makeNSView(context _: Context) -> NSProgressIndicator {
.init()
}
@available(macOS 10.15, *)
func updateNSView(_ view: NSProgressIndicator, context _: Context) {
if let value = configuration.fractionCompleted {
view.doubleValue = value
@ -65,13 +71,16 @@ extension BackportProgressViewStyle where Self == Backport<Any>.CircularProgress
}
#elseif !os(watchOS)
@available(macOS 10.15, *)
private struct CircularRepresentable: UIViewRepresentable {
let configuration: Backport<Any>.ProgressViewStyleConfiguration
@available(macOS 10.15, *)
func makeUIView(context _: Context) -> UIActivityIndicatorView {
.init(style: .medium)
}
@available(macOS 10.15, *)
func updateUIView(_ view: UIActivityIndicatorView, context _: Context) {
view.hidesWhenStopped = false
view.startAnimating()

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -17,6 +18,7 @@ extension Backport where Wrapped == Any {
/// Creates a default progress view style.
public init() {}
@available(macOS 10.15, *)
/// Creates a view representing the body of a progress view.
///
/// - Parameter configuration: The properties of the progress view being
@ -46,6 +48,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.DefaultProgressViewStyle {
public static var automatic: Self { .init() }
}

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14)
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14.0)
@ -26,6 +27,7 @@ extension Backport where Wrapped == Any {
///
/// - Parameter configuration: The properties of the progress view, such as
/// its preferred progress type.
@available(macOS 10.15, *)
public func makeBody(configuration: Configuration) -> some View {
#if os(macOS)
VStack(alignment: .leading, spacing: 0) {
@ -60,18 +62,22 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension BackportProgressViewStyle where Self == Backport<Any>.LinearProgressViewStyle {
public static var linear: Self { .init() }
}
#if os(macOS)
@available(macOS 10.15, *)
private struct LinearRepresentable: NSViewRepresentable {
let configuration: Backport<Any>.ProgressViewStyleConfiguration
@available(macOS 10.15, *)
func makeNSView(context _: Context) -> NSProgressIndicator {
.init()
}
@available(macOS 10.15, *)
func updateNSView(_ view: NSProgressIndicator, context _: Context) {
if let value = configuration.fractionCompleted {
view.doubleValue = value
@ -88,13 +94,16 @@ extension BackportProgressViewStyle where Self == Backport<Any>.LinearProgressVi
}
#elseif !os(watchOS)
@available(macOS 10.15, *)
private struct LinearRepresentable: UIViewRepresentable {
let configuration: Backport<Any>.ProgressViewStyleConfiguration
@available(macOS 10.15, *)
func makeUIView(context _: Context) -> UIProgressView {
.init(progressViewStyle: .default)
}
@available(macOS 10.15, *)
func updateUIView(_ view: UIProgressView, context _: Context) {
view.progress = Float(configuration.fractionCompleted ?? 0)
}

View File

@ -8,6 +8,7 @@ import SwiftUI
import QuickLook
import QuickLookUI
@available(macOS 10.15, *)
final class PreviewController<Items>: NSViewController, QLPreviewPanelDataSource, QLPreviewPanelDelegate
where Items: RandomAccessCollection, Items.Element == URL {
private let panel = QLPreviewPanel.shared()!

View File

@ -12,6 +12,7 @@ import SwiftUI
@available(macOS, deprecated: 11)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Presents a Quick Look preview of the URLs you provide.
///
@ -61,6 +62,7 @@ extension Backport where Wrapped: View {
#if os(macOS)
import QuickLookUI
@available(macOS 10.15, *)
private struct QuicklookSheet<Items>: NSViewControllerRepresentable
where Items: RandomAccessCollection, Items.Element == URL {
let selection: Binding<Items.Element?>

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 15)
@available(macOS, deprecated: 12)
@available(tvOS, deprecated: 15)
@ -81,6 +82,7 @@ extension Backport where Wrapped: View {
@available(macOS, deprecated: 12)
@available(tvOS, deprecated: 15)
@available(watchOS, deprecated: 8)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// An action that initiates a refresh operation.
///
@ -134,6 +136,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
private struct RefreshEnvironmentKey: EnvironmentKey {
static let defaultValue: Backport<Any>.RefreshAction? = nil
}
@ -142,6 +145,7 @@ private struct RefreshEnvironmentKey: EnvironmentKey {
@available(macOS, deprecated: 12)
@available(tvOS, deprecated: 15)
@available(watchOS, deprecated: 8)
@available(macOS 10.15, *)
extension EnvironmentValues {
/// An action that initiates a refresh operation.
///

View File

@ -2,6 +2,7 @@ import StoreKit
import SwiftUI
#if os(iOS) || os(macOS)
@available(macOS 10.15, *)
extension EnvironmentValues {
/// An instance that tells StoreKit to request an App Store rating or review from the user, if appropriate.
/// Read the requestReview environment value to get an instance of this structure for a given Environment. Call the instance to tell StoreKit to ask the user to rate or review your app, if appropriate. You call the instance directly because it defines a callAsFunction() method that Swift calls when you call the instance.
@ -19,6 +20,7 @@ import SwiftUI
///
/// > When you call this instance while your app is in development mode, the system always displays a rating and review request view so you can test the user interface and experience. This instance has no effect when you call it in an app that you distribute using TestFlight.
///
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(macOS, deprecated: 13)
extension Backport where Wrapped == Any {

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 15)
@available(tvOS, deprecated: 15)
@available(macOS, deprecated: 12)
@ -20,6 +21,7 @@ extension Backport where Wrapped == Any {
@ViewBuilder let header: () -> Parent
@ViewBuilder let footer: () -> Footer
@available(macOS 10.15, *)
public var body: some View {
SwiftUI.Section(
content: content,
@ -30,6 +32,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
extension Backport.Section where Wrapped == Any, Parent == Text, Footer == EmptyView {
/// Creates a section with the provided section content.
/// - Parameters:
@ -42,6 +45,7 @@ extension Backport.Section where Wrapped == Any, Parent == Text, Footer == Empty
footer = { EmptyView() }
}
@available(macOS 10.15, *)
/// Creates a section with the provided section content.
/// - Parameters:
/// - title: A string that describes the contents of the section.

View File

@ -1,6 +1,7 @@
import Combine
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 14.0)
@available(macOS, deprecated: 11.0)
@available(tvOS, deprecated: 14.0)
@ -48,6 +49,7 @@ extension Backport where Wrapped: ObservableObject {
private final class Wrapper: ObservableObject {
private var subject = PassthroughSubject<Void, Never>()
@available(macOS 10.15, *)
var value: Wrapped? {
didSet {
cancellable = nil
@ -56,19 +58,25 @@ extension Backport where Wrapped: ObservableObject {
}
}
@available(macOS 10.15, *)
private var cancellable: AnyCancellable?
@available(macOS 10.15, *)
var objectWillChange: AnyPublisher<Void, Never> {
subject.eraseToAnyPublisher()
}
}
@available(macOS 10.15, *)
@State private var state = Wrapper()
@available(macOS 10.15, *)
@ObservedObject private var observedObject = Wrapper()
@available(macOS 10.15, *)
private var thunk: () -> Wrapped
@available(macOS 10.15, *)
/// The underlying value referenced by the state object.
///
/// The wrapped value property provides primary access to the value's data.
@ -94,6 +102,7 @@ extension Backport where Wrapped: ObservableObject {
}
}
@available(macOS 10.15, *)
/// A projection of the state object that creates bindings to its
/// properties.
///
@ -113,6 +122,7 @@ extension Backport where Wrapped: ObservableObject {
ObservedObject(wrappedValue: wrappedValue).projectedValue
}
@available(macOS 10.15, *)
/// Creates a new state object with an initial wrapped value.
///
/// You dont call this initializer directly. Instead, declare a property
@ -136,6 +146,7 @@ extension Backport where Wrapped: ObservableObject {
self.thunk = thunk
}
@available(macOS 10.15, *)
public mutating func update() {
if state.value == nil {
state.value = thunk()

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 15.0)
@available(macOS, deprecated: 12.0)
@available(tvOS, deprecated: 15.0)
@ -64,6 +65,7 @@ extension Backport where Wrapped: View {
)
}
@available(macOS 10.15, *)
/// Adds a task to perform when this view appears or when a specified
/// value changes.
///
@ -137,19 +139,23 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
private struct TaskModifier<ID: Equatable>: ViewModifier {
var id: ID
var priority: TaskPriority
var action: () async -> Void
@available(macOS 10.15, *)
@State private var task: Task<Void, Never>?
@available(macOS 10.15, *)
init(id: ID, priority: TaskPriority, action: @MainActor @escaping () async -> Void) {
self.id = id
self.priority = priority
self.action = action
}
@available(macOS 10.15, *)
func body(content: Content) -> some View {
content
.backport.onChange(of: id) { _ in

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped == AnyTransition {
/// Creates a transition that when added to a view will animate the views insertion by moving it in from the specified edge while fading it in, and animate its removal by moving it out towards the opposite edge and fading it out.
/// - Parameter edge: the edge from which the view will be animated in.

View File

@ -4,6 +4,7 @@
import Foundation
@available(macOS 10.15, *)
@available(iOS, deprecated: 15.0)
@available(macOS, deprecated: 12.0)
@available(tvOS, deprecated: 15.0)
@ -152,6 +153,7 @@ extension Backport where Wrapped: URLSession {
}
}
@available(macOS 10.15, *)
private actor URLSessionTaskActor {
weak var task: URLSessionTask?

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 15)
@available(macOS, deprecated: 12)
@available(tvOS, deprecated: 15)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@available(watchOS, deprecated: 9)
@ -39,6 +40,7 @@ extension Backport where Wrapped: View {
#endif
}
@available(macOS 10.15, *)
/// Sets the available detents for the enclosing sheet, giving you
/// programmatic control of the currently selected detent.
///
@ -81,6 +83,7 @@ extension Backport where Wrapped: View {
#endif
}
@available(macOS 10.15, *)
/// Sets the available detents for the enclosing sheet, giving you
/// programmatic control of the currently selected detent.
///
@ -126,6 +129,7 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -139,32 +143,39 @@ extension Backport where Wrapped == Any {
self.rawValue = rawValue
}
@available(macOS 10.15, *)
public static var medium: Identifier {
.init(rawValue: "com.apple.UIKit.medium")
}
@available(macOS 10.15, *)
public static var large: Identifier {
.init(rawValue: "com.apple.UIKit.large")
}
}
@available(macOS 10.15, *)
public let id: Identifier
@available(macOS 10.15, *)
/// The system detent for a sheet that's approximately half the height of
/// the screen, and is inactive in compact height.
public static var medium: PresentationDetent {
.init(id: .medium)
}
@available(macOS 10.15, *)
/// The system detent for a sheet at full height.
public static var large: PresentationDetent {
.init(id: .large)
}
@available(macOS 10.15, *)
fileprivate static var none: PresentationDetent {
.init(id: .init(rawValue: ""))
}
@available(macOS 10.15, *)
public static func < (lhs: PresentationDetent, rhs: PresentationDetent) -> Bool {
switch (lhs, rhs) {
case (.large, .medium):
@ -194,6 +205,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
@available(iOS 15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController, UISheetPresentationControllerDelegate {
@ -202,6 +214,7 @@ extension Backport where Wrapped == Any {
var largestUndimmed: Backport<Any>.PresentationDetent?
weak var _delegate: UISheetPresentationControllerDelegate?
@available(macOS 10.15, *)
init(
detents: Set<Backport<Any>.PresentationDetent>, selection: Binding<Backport<Any>.PresentationDetent>?,
largestUndimmed: Backport<Any>.PresentationDetent?
@ -212,11 +225,13 @@ extension Backport where Wrapped == Any {
super.init(nibName: nil, bundle: nil)
}
@available(macOS 10.15, *)
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@available(macOS 10.15, *)
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
if let controller = parent?.sheetPresentationController {
@ -228,6 +243,7 @@ extension Backport where Wrapped == Any {
update(detents: detents, selection: selection, largestUndimmed: largestUndimmed)
}
@available(macOS 10.15, *)
func update(
detents: Set<Backport<Any>.PresentationDetent>, selection: Binding<Backport<Any>.PresentationDetent>?,
largestUndimmed: Backport<Any>.PresentationDetent?
@ -269,6 +285,7 @@ extension Backport where Wrapped == Any {
}
}
@available(macOS 10.15, *)
func sheetPresentationControllerDidChangeSelectedDetentIdentifier(
_ sheetPresentationController: UISheetPresentationController
) {
@ -281,12 +298,14 @@ extension Backport where Wrapped == Any {
selection.wrappedValue = .init(id: .init(rawValue: id))
}
@available(macOS 10.15, *)
override func responds(to aSelector: Selector!) -> Bool {
if super.responds(to: aSelector) { return true }
if _delegate?.responds(to: aSelector) ?? false { return true }
return false
}
@available(macOS 10.15, *)
override func forwardingTarget(for aSelector: Selector!) -> Any? {
if super.responds(to: aSelector) { return self }
return _delegate

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -46,6 +47,7 @@ extension Backport where Wrapped: View {
#if os(iOS)
@available(iOS 15, *)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
let visibility: Backport<Any>.Visibility
@ -60,26 +62,31 @@ extension Backport where Wrapped: View {
}
}
@available(macOS 10.15, *)
@available(iOS 15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController {
var visibility: Backport<Any>.Visibility
@available(macOS 10.15, *)
init(visibility: Backport<Any>.Visibility) {
self.visibility = visibility
super.init(nibName: nil, bundle: nil)
}
@available(macOS 10.15, *)
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@available(macOS 10.15, *)
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
update(visibility: visibility)
}
@available(macOS 10.15, *)
func update(visibility: Backport<Any>.Visibility) {
self.visibility = visibility

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@available(watchOS, deprecated: 9)
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Removes dimming from detents higher (and including) the provided identifier
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Conditionally prevents interactive dismissal of a popover or a sheet.
///
@ -87,6 +88,7 @@ extension Backport where Wrapped: View {
#endif
}
@available(macOS 10.15, *)
/// Conditionally prevents interactive dismissal of a popover or a sheet. In addition, provides fine-grained control over the dismissal
///
/// Users can dismiss certain kinds of presentations using built-in
@ -169,38 +171,45 @@ extension Backport where Wrapped: View {
}
#if os(iOS)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
fileprivate struct Representable: UIViewControllerRepresentable {
let isModal: Bool
let onAttempt: (() -> Void)?
@available(macOS 10.15, *)
func makeUIViewController(context _: Context) -> Backport.Representable.Controller {
Controller(isModal: isModal, onAttempt: onAttempt)
}
@available(macOS 10.15, *)
func updateUIViewController(_ controller: Backport.Representable.Controller, context _: Context) {
controller.update(isModal: isModal, onAttempt: onAttempt)
}
}
}
@available(macOS 10.15, *)
extension Backport.Representable {
fileprivate final class Controller: UIViewController, UIAdaptivePresentationControllerDelegate {
var isModal: Bool
var onAttempt: (() -> Void)?
weak var _delegate: UIAdaptivePresentationControllerDelegate?
@available(macOS 10.15, *)
init(isModal: Bool, onAttempt: (() -> Void)?) {
self.isModal = isModal
self.onAttempt = onAttempt
super.init(nibName: nil, bundle: nil)
}
@available(macOS 10.15, *)
@available(*, unavailable)
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@available(macOS 10.15, *)
override func willMove(toParent parent: UIViewController?) {
super.willMove(toParent: parent)
if let controller = parent?.presentationController {
@ -212,6 +221,7 @@ extension Backport where Wrapped: View {
update(isModal: isModal, onAttempt: onAttempt)
}
@available(macOS 10.15, *)
func update(isModal: Bool, onAttempt: (() -> Void)?) {
self.isModal = isModal
self.onAttempt = onAttempt
@ -219,20 +229,24 @@ extension Backport where Wrapped: View {
parent?.isModalInPresentation = isModal
}
@available(macOS 10.15, *)
func presentationControllerDidAttemptToDismiss(_: UIPresentationController) {
onAttempt?()
}
@available(macOS 10.15, *)
func presentationControllerShouldDismiss(_: UIPresentationController) -> Bool {
parent?.isModalInPresentation == false
}
@available(macOS 10.15, *)
override func responds(to aSelector: Selector!) -> Bool {
if super.responds(to: aSelector) { return true }
if _delegate?.responds(to: aSelector) ?? false { return true }
return false
}
@available(macOS 10.15, *)
override func forwardingTarget(for aSelector: Selector!) -> Any? {
if super.responds(to: aSelector) { return self }
return _delegate

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(macOS, deprecated: 11)
@available(tvOS, deprecated: 14)
@available(watchOS, deprecated: 7)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// A dynamic property that scales a numeric value.
@propertyWrapper

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -16,6 +17,7 @@ extension EnvironmentValues {
set { self[BackportVerticalIndicatorKey.self] = newValue }
}
@available(macOS 10.15, *)
/// The visibility to apply to scroll indicators of any
/// horizontally scrollable content.
public var backportHorizontalScrollIndicatorVisibility: Backport<Any>.ScrollIndicatorVisibility {
@ -23,6 +25,7 @@ extension EnvironmentValues {
set { self[BackportHorizontalIndicatorKey.self] = newValue }
}
@available(macOS 10.15, *)
/// The way that scrollable content interacts with the software keyboard.
///
/// The default value is ``Backport.ScrollDismissesKeyboardMode.automatic``. Use the
@ -33,6 +36,7 @@ extension EnvironmentValues {
set { self[BackportKeyboardDismissKey.self] = newValue }
}
@available(macOS 10.15, *)
/// A Boolean value that indicates whether any scroll views associated
/// with this environment allow scrolling to occur.
///
@ -44,18 +48,22 @@ extension EnvironmentValues {
}
}
@available(macOS 10.15, *)
private struct BackportVerticalIndicatorKey: EnvironmentKey {
static var defaultValue: Backport<Any>.ScrollIndicatorVisibility = .automatic
}
@available(macOS 10.15, *)
private struct BackportHorizontalIndicatorKey: EnvironmentKey {
static var defaultValue: Backport<Any>.ScrollIndicatorVisibility = .automatic
}
@available(macOS 10.15, *)
private struct BackportKeyboardDismissKey: EnvironmentKey {
static var defaultValue: Backport<Any>.ScrollDismissesKeyboardMode = .automatic
}
@available(macOS 10.15, *)
private struct BackportScrollEnabledKey: EnvironmentKey {
static var defaultValue: Bool = true
}

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@available(watchOS, deprecated: 9)
@available(macOS 10.15, *)
extension Backport where Wrapped == Any {
/// The ways that scrollable content can interact with the software keyboard.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@ -20,22 +21,27 @@ extension Backport where Wrapped == Any {
case hidden
}
@available(macOS 10.15, *)
let visibility: Backport.Visibility
@available(macOS 10.15, *)
var scrollViewVisible: Bool {
visibility != .hidden
}
@available(macOS 10.15, *)
public var description: String {
String(describing: visibility)
}
@available(macOS 10.15, *)
/// Scroll indicator visibility depends on the
/// policies of the component accepting the visibility configuration.
public static var automatic: ScrollIndicatorVisibility {
.init(visibility: .automatic)
}
@available(macOS 10.15, *)
/// Show the scroll indicators.
///
/// The actual visibility of the indicators depends on platform
@ -45,6 +51,7 @@ extension Backport where Wrapped == Any {
.init(visibility: .visible)
}
@available(macOS 10.15, *)
/// Hide the scroll indicators.
///
/// By default, scroll views in macOS show indicators when a

View File

@ -8,6 +8,7 @@ import SwiftUI
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)
@available(watchOS, deprecated: 9)
@available(macOS 10.15, *)
extension Backport where Wrapped: View {
/// Sets the visibility of scroll indicators within this view.
///

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
@available(iOS, deprecated: 16)
@available(tvOS, deprecated: 16)
@available(macOS, deprecated: 13)

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
/// Provides optional inset values. `nil` is interpreted as: use system default
internal struct ProposedInsets: Equatable {
/// The proposed leading margin measured in points.
@ -11,24 +12,29 @@ internal struct ProposedInsets: Equatable {
/// A value of `nil` tells the system to use a default value
public var leading: CGFloat?
@available(macOS 10.15, *)
/// The proposed trailing margin measured in points.
///
/// A value of `nil` tells the system to use a default value
public var trailing: CGFloat?
@available(macOS 10.15, *)
/// The proposed top margin measured in points.
///
/// A value of `nil` tells the system to use a default value
public var top: CGFloat?
@available(macOS 10.15, *)
/// The proposed bottom margin measured in points.
///
/// A value of `nil` tells the system to use a default value
public var bottom: CGFloat?
@available(macOS 10.15, *)
/// An insets proposal with all dimensions left unspecified.
public static var unspecified: ProposedInsets { .init() }
@available(macOS 10.15, *)
/// An insets proposal that contains zero for all dimensions.
public static var zero: ProposedInsets { .init(leading: 0, trailing: 0, top: 0, bottom: 0) }
}

View File

@ -4,6 +4,7 @@
import SwiftUI
@available(macOS 10.15, *)
/// A proposal for the size
///
/// * The ``zero`` proposal; the size responds with its minimum size.
@ -15,24 +16,29 @@ internal struct ProposedSize: Equatable, Sendable {
/// A value of `nil` represents an unspecified width proposal.
public var width: CGFloat?
@available(macOS 10.15, *)
/// The proposed vertical size measured in points.
///
/// A value of `nil` represents an unspecified height proposal.
public var height: CGFloat?
@available(macOS 10.15, *)
/// A size proposal that contains zero in both dimensions.
public static var zero: ProposedSize { .init(width: 0, height: 0) }
@available(macOS 10.15, *)
/// The proposed size with both dimensions left unspecified.
///
/// Both dimensions contain `nil` in this size proposal.
public static var unspecified: ProposedSize { .init(width: nil, height: nil) }
@available(macOS 10.15, *)
/// A size proposal that contains infinity in both dimensions.
///
/// Both dimensions contain .infinity in this size proposal.
public static var infinity: ProposedSize { .init(width: .infinity, height: .infinity) }
@available(macOS 10.15, *)
/// Creates a new proposed size using the specified width and height.
///
/// - Parameters:
@ -45,6 +51,7 @@ internal struct ProposedSize: Equatable, Sendable {
self.height = height
}
@available(macOS 10.15, *)
/// Creates a new proposed size from a specified size.
///
/// - Parameter size: A proposed size with dimensions measured in points.