From caa8e6bb6e6a38420e97310f05e1b7ef29794eef Mon Sep 17 00:00:00 2001 From: david-swift Date: Fri, 3 Jan 2025 09:14:12 +0100 Subject: [PATCH] Add support for sheets --- Sources/Core/View/SheetWrapper.swift | 100 +++++++++++++++++++++++++++ Sources/MacBackend/AnyView.swift | 12 ++++ 2 files changed, 112 insertions(+) create mode 100644 Sources/Core/View/SheetWrapper.swift diff --git a/Sources/Core/View/SheetWrapper.swift b/Sources/Core/View/SheetWrapper.swift new file mode 100644 index 0000000..5e836ac --- /dev/null +++ b/Sources/Core/View/SheetWrapper.swift @@ -0,0 +1,100 @@ +// +// SheetWrapper.swift +// MacBackend +// +// Created by david-swift on 31.12.2024. +// + +import SwiftUI + +/// A sheet on top of a wrapped view. +public struct SheetWrapper: SwiftUIWidget { + + /// Whether the sheet is presented. + @Meta.Binding var isPresented: Bool + /// The wrapped view. + var content: Body + /// The dialog's content. + var dialog: Body + /// The cancellation action. + var cancellationAction: Body = [] + /// The confirmation action. + var confirmationAction: Body = [] + /// The toolbar's content. + var toolbar: Body = [] + + /// The wrapped views. + public var wrappedViews: [String: Meta.AnyView] { + [ + .mainContent: content, + "dialog": dialog, + "cancellationAction": cancellationAction, + "confirmationAction": confirmationAction, + "toolbar": toolbar + ] + } + + /// Initialize a sheet wrapper. + /// - Parameters: + /// - isPresented: Whether the sheet is presented. + /// - content: The wrapped view. + /// - dialog: The dialog's content. + public init( + isPresented: Meta.Binding, + @Meta.ViewBuilder content: () -> Body, + @Meta.ViewBuilder dialog: () -> Body + ) { + self._isPresented = isPresented + self.content = content() + self.dialog = dialog() + } + + /// Get the SwiftUI view. + /// - Parameter properties: The widget data. + /// - Returns: The SwiftUI view. + public static func view(properties: Self) -> some SwiftUI.View { + MacBackendView(.mainContent) + .sheet(isPresented: properties._isPresented.swiftUI) { + MacBackendView("dialog") + .toolbar { + if !properties.cancellationAction.isEmpty { + ToolbarItem(placement: .cancellationAction) { + MacBackendView("cancellationAction") + } + } + if !properties.confirmationAction.isEmpty { + ToolbarItem(placement: .confirmationAction) { + MacBackendView("confirmationAction") + } + } + if !properties.toolbar.isEmpty { + ToolbarItem { + MacBackendView("toolbar") + } + } + } + } + } + + /// Set the cancellation action in the toolbar. + /// - Parameter action: The action view. + /// - Returns: The sheet wrapper. + public func cancellationAction(@Meta.ViewBuilder _ action: () -> Body) -> Self { + modify { $0.cancellationAction = action() } + } + + /// Set the confirmation action in the toolbar. + /// - Parameter action: The action view. + /// - Returns: The sheet wrapper. + public func confirmationAction(@Meta.ViewBuilder _ action: () -> Body) -> Self { + modify { $0.confirmationAction = action() } + } + + /// Set the sheet's toolbar. + /// - Parameter action: The toolbar view. + /// - Returns: The sheet wrapper. + public func sheetToolbar(@Meta.ViewBuilder _ toolbar: () -> Body) -> Self { + modify { $0.toolbar = toolbar() } + } + +} diff --git a/Sources/MacBackend/AnyView.swift b/Sources/MacBackend/AnyView.swift index 252a16f..cb9a5ec 100644 --- a/Sources/MacBackend/AnyView.swift +++ b/Sources/MacBackend/AnyView.swift @@ -60,4 +60,16 @@ extension AnyView { ToolbarView(child: self, type: .center, toolbarViews: content) } + /// Present a sheet on top of the window. + /// - Parameters: + /// - isPresented: Whether the sheet is presented. + /// - dialog: The dialog's content. + /// - Returns: The wrapped view. + public func sheet( + isPresented: Meta.Binding, + @Meta.ViewBuilder dialog: () -> Body + ) -> SheetWrapper { + .init(isPresented: isPresented, content: { self }, dialog: dialog) + } + }