diff --git a/Sources/LiveViewNative/LiveViewNative.docc/LiveViewNative.md b/Sources/LiveViewNative/LiveViewNative.docc/LiveViewNative.md index 40f1b1fda..934045b18 100644 --- a/Sources/LiveViewNative/LiveViewNative.docc/LiveViewNative.md +++ b/Sources/LiveViewNative/LiveViewNative.docc/LiveViewNative.md @@ -88,6 +88,7 @@ be found at . - - - +- - - - diff --git a/Sources/LiveViewNative/Modifiers/Modal Presentations/AlertModifier.swift b/Sources/LiveViewNative/Modifiers/Modal Presentations/AlertModifier.swift new file mode 100644 index 000000000..967b428f5 --- /dev/null +++ b/Sources/LiveViewNative/Modifiers/Modal Presentations/AlertModifier.swift @@ -0,0 +1,107 @@ +// +// AlertModifier.swift +// LiveViewNative +// +// Created by Shadowfacts on 4/28/23. +// + +import SwiftUI + +/// Displays a system-style alert when a live binding is active. +/// +/// ```html +/// +/// +/// +/// ``` +/// +/// ```elixir +/// defmodule AppWeb.TestLive do +/// use AppWeb, :live_view +/// use LiveViewNative.LiveView +/// +/// native_binding :show, Atom, false +/// end +/// ``` +/// +/// ## Arguments +/// - ``title`` +/// - ``actions`` +/// - ``message`` +/// - ``isPresented`` +#if swift(>=5.8) +@_documentation(visibility: public) +#endif +struct AlertModifier: ViewModifier, Decodable { + /// The title of the alert. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let title: String + + /// A reference to a set of ``Button`` views that are used as the actions for the alert. + /// + /// The system will dismiss the alert when any of the buttons is activated. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let actions: String + + /// A reference to an optional ``Text`` view to use as the alert's message. + /// + /// If no reference is provided, the alert will not have a message. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + private let message: String? + + /// The name of a live binding that controls when the alert is shown. + /// + /// Set the binding to `true` to show the alert. + #if swift(>=5.8) + @_documentation(visibility: public) + #endif + @LiveBinding private var isPresented: Bool + + @ObservedElement private var element + @LiveContext private var context + + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.title = try container.decode(String.self, forKey: .title) + self.actions = try container.decode(String.self, forKey: .actions) + self.message = try container.decodeIfPresent(String.self, forKey: .message) + self._isPresented = try LiveBinding(decoding: .isPresented, in: container) + } + + func body(content: Content) -> some View { + content.alert(title, isPresented: $isPresented) { + context.buildChildren(of: element, withTagName: self.actions, namespace: "alert") + } message: { + if let message { + context.buildChildren(of: element, withTagName: message, namespace: "alert") + } + } + } + + enum CodingKeys: String, CodingKey { + case title + case actions + case message + case isPresented = "is_presented" + } +} diff --git a/lib/live_view_native_swift_ui/modifiers/modal_presentations/alert.ex b/lib/live_view_native_swift_ui/modifiers/modal_presentations/alert.ex new file mode 100644 index 000000000..80d513715 --- /dev/null +++ b/lib/live_view_native_swift_ui/modifiers/modal_presentations/alert.ex @@ -0,0 +1,12 @@ +defmodule LiveViewNativeSwiftUi.Modifiers.Alert do + use LiveViewNativePlatform.Modifier + + alias LiveViewNativeSwiftUi.Types.{KeyName, NativeBindingName} + + modifier_schema "alert" do + field(:title, :string) + field(:actions, KeyName) + field(:message, KeyName, default: nil) + field(:is_presented, NativeBindingName) + end +end diff --git a/lib/live_view_native_swift_ui/types/key_name.ex b/lib/live_view_native_swift_ui/types/key_name.ex index ef5af66d0..b474fab0c 100644 --- a/lib/live_view_native_swift_ui/types/key_name.ex +++ b/lib/live_view_native_swift_ui/types/key_name.ex @@ -2,6 +2,10 @@ defmodule LiveViewNativeSwiftUi.Types.KeyName do use LiveViewNativePlatform.Modifier.Type def type, do: :string - def cast(value) when is_atom(value) and not is_nil(value) and not is_boolean(value), do: {:ok, Atom.to_string(value)} + def cast(nil), do: nil + + def cast(value) when is_atom(value) and not is_boolean(value), + do: {:ok, Atom.to_string(value)} + def cast(_), do: :error end