diff --git a/Sources/Interact/Model/Prompt.swift b/Sources/Interact/Model/Prompt.swift new file mode 100644 index 00000000000..3c4d09d3d38 --- /dev/null +++ b/Sources/Interact/Model/Prompt.swift @@ -0,0 +1,46 @@ +// Copyright (c) 2018-2026 Jason Morley +// +// 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 NONINFRINGEMENT. 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. + +import SwiftUI + +public protocol Promptable { + + associatedtype Actions: View + associatedtype Message: View + + var title: String { get } + var actions: Actions { get } + var message: Message { get } + +} + +public struct Prompt: Promptable { + + public let title: String + public let actions: Actions + public let message: Message + + public init(_ title: String, @ViewBuilder actions: () -> Actions, @ViewBuilder message: () -> Message) { + self.title = title + self.actions = actions() + self.message = message() + } + +} diff --git a/Sources/Interact/Modifiers/PromptModifier.swift b/Sources/Interact/Modifiers/PromptModifier.swift new file mode 100644 index 00000000000..896b0cc35d2 --- /dev/null +++ b/Sources/Interact/Modifiers/PromptModifier.swift @@ -0,0 +1,48 @@ +// Copyright (c) 2018-2026 Jason Morley +// +// 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 NONINFRINGEMENT. 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. + +import SwiftUI + +struct PromptModifier: ViewModifier { + + @Binding var item: T? + + let content: (T) -> A + + func body(content: Content) -> some View { + let alertContent = item.map(self.content) + return content.alert(alertContent?.title ?? "", + isPresented: $item.bool(), + presenting: alertContent) { alertContent in + alertContent.actions + } message: { alertContent in + alertContent.message + } + } +} + +public extension View { + + func prompt(item: Binding, + content: @escaping (T) -> A) -> some View { + self.modifier(PromptModifier(item: item, content: content)) + } + +}