Skip to content

Commit

Permalink
Add alert modifier
Browse files Browse the repository at this point in the history
Closes #636

Also permits nil for template key names, allowing for optional templates
  • Loading branch information
shadowfacts committed Apr 28, 2023
1 parent e040f35 commit 0308d66
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ be found at <https://hexdocs.pm/live_view_native_swift_ui>.
- <doc:LayoutAdjustmentsModifiers>
- <doc:LayoutFundamentalsModifiers>
- <doc:ListsModifiers>
- <doc:ModalPresentations>
- <doc:NavigationModifiers>
- <doc:TextInputAndOutputModifiers>
- <doc:ViewFundamentalsModifiers>
Expand Down
Original file line number Diff line number Diff line change
@@ -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
/// <Button phx-click="toggle-show"
/// modifiers={
/// @native
/// |> alert(title: "My Alert", message: :message, actions: :actions, is_presented: :show)
/// }
/// >
/// Present Alert
/// <alert:message>
/// Hello, world!
/// </alert:message>
/// <alert:actions>
/// <Button>
/// OK
/// </Button>
/// </alert:actions>
/// </Button>
/// ```
///
/// ```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<R: RootRegistry>: 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<R> 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"
}
}
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion lib/live_view_native_swift_ui/types/key_name.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 0308d66

Please sign in to comment.