CoolONEOfficial / NativePartialSheet

🔥 Native partial customizable SwiftUI sheets from iOS 15.0
MIT License
119 stars 7 forks source link
modals sheet swiftui

NativePartialSheet

Main feature of this library - native support of custom SwiftUI's presentationDetents from iOS 15.0 🔥

Screenshots

Simple examples

Classic isPresented way

import SwiftUI
import NativePartialSheet

struct ContentView: View {
    @State var isPresented = false

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                isPresented = true
            }
            .nativePartialSheet(isPresented: $isPresented) {
                Text("Sheet content")
            }
            .presentationDetents([ .large, .medium ])
    }
}

Optional detent way

import SwiftUI
import NativePartialSheet

struct ContentView: View {
    @State var detent: Detent?

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                detent = .medium
            }
            .nativePartialSheet(selectedDetent: $detent) { detent in
                switch detent {
                case .medium:
                    Text("Medium")
                case .large:
                    Text("Large")
                default:
                    EmptyView()
                }
            }
            .presentationDetents([ .large, .medium ])
    }
}

Advanced examples

Sheet configuration

import SwiftUI
import NativePartialSheet

struct ContentView: View {
    @State var isPresented = false
    @State var detent: Detent = .medium

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                isPresented = true
            }
            .nativePartialSheet(isPresented: $isPresented) {
                Text("Sheet content")
            }
            .presentationDetents([ .medium, .large ], selection: $detent)
            .cornerRadius(32)
            .presentationDragIndicator(.visible)
            .edgeAttachedInCompactHeight(true)
            .scrollingExpandsWhenScrolledToEdge(true)
            .widthFollowsPreferredContentSizeWhenEdgeAttached(true)
            .largestUndimmedDetent(.medium)
            .interactiveDismissDisabled(true, onWillDismiss: onWillDismiss, onDidDismiss: onDidDismiss)
    }

    func onDidDismiss() {
        debugPrint("DID")
    }

    func onWillDismiss() {
        debugPrint("WILL")
    }
}

Use with item

import SwiftUI
import NativePartialSheet

struct MyItem: Identifiable {
    var content: String
    var id: String { content }
}

struct ContentView: View {
    @State var item: MyItem?

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                item = .init(content: "Test content")
            }
            .nativePartialSheet(item: $item) { item in
                VStack {
                    Button("recreate") {
                        self.item = .init(content: "Recreated content")
                    }
                    Button("change") {
                        self.item?.content = "Changed content"
                    }
                    Text(item.content)
                }
            }
            .presentationDetents([ .large, .medium ])
    }
}

Custom static detents

import SwiftUI
import NativePartialSheet

extension Detent {
    static let customSmall: Detent = .height(100)
}

struct ContentView: View {
    @State var detent: Detent?

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                detent = .customSmall
            }
            .nativePartialSheet(selectedDetent: $detent) { detent in
                switch detent {
                case .medium:
                    Text("Medium")
                case .large:
                    Text("Large")
                case .customSmall:
                    Text("Custom small")
                default:
                    EmptyView()
                }
            }
            .presentationDetents([ .large, .medium, .customSmall ])
    }
}

Custom dynamic detents

import SwiftUI
import NativePartialSheet

struct ContentView: View {
    @State var detent: Detent?
    @State var detents: Set<Detent> = [ .large, .medium ]

    var body: some View {
        Text("Open sheet")
            .onTapGesture {
                let dynamic = Detent.height(123)
                detents.insert(dynamic)
                detent = dynamic
            }
            .nativePartialSheet(selectedDetent: $detent) { detent in
                switch detent {
                case .height(_):
                    Text("Dynamic")
                case .medium:
                    Text("Medium")
                case .large:
                    Text("Large")
                }
            }
            .presentationDetents(detents)
    }
}