defmodule PrimerLive.Helpers.PromptDeclarationHelpers do @moduledoc false alias Phoenix.LiveView.JS defmacro id(name_element_id, the_element, is_required) do quote do attr(:id, :string, required: unquote(is_required), doc: if unquote(is_required) do """ {name_element_id}, used for opening and closing from the outside. """ |> String.replace("{name_element_id}", unquote(name_element_id)) else """ {name_element_id}. While passing the ID is optional, it is required: - For referencing {the_element} from other functions or components, such as for opening and closing. - For maintaining an open state after making selections. - To get consistent IDs in tests. If not set, an ID is derived from `form` and `field`, or otherwise generated randomly. """ |> String.replace("{name_element_id}", unquote(name_element_id)) |> String.replace("{the_element}", unquote(the_element)) end ) end end defmacro is_dropdown_caret(default) do quote do attr :is_dropdown_caret, :boolean, default: unquote(default), doc: "Adds a dropdown caret icon to the toggle button." end end defmacro is_backdrop do quote do attr :is_backdrop, :boolean, default: false, doc: """ Generates a backdrop background with a default strength and tint values. Default backdrop strenght: - dialog and drawer: `"medium"` - menus: `"light"` Default tint: "dark". """ end end defmacro backdrop_strength do quote do attr :backdrop_strength, :string, values: ["medium", "strong", "light", nil], default: nil, doc: """ Backdrop strenght. Overrides the default value from `is_backdrop`. """ end end defmacro backdrop_tint do quote do attr :backdrop_tint, :string, values: ["dark", "light", nil], default: nil, doc: """ Backdrop tint. Overrides the default value from `is_backdrop`. """ end end defmacro is_fast(default_value) do quote do attr :is_fast, :boolean, default: unquote(default_value), doc: """ Generates fast fade transitions for backdrop and content. """ end end defmacro toggle_slot(the_element) do quote do slot :toggle, required: true, doc: """ Generates a button to open {the_element}. A `phx-click` attribute is added automatically if it is not passed in the slot attributes. Any custom class will override the default class "btn". """ |> String.replace("{the_element}", unquote(the_element)) do attr(:class, :any, doc: """ Additional classname. """ ) attr(:style, :string, doc: """ Additional CSS styles. """ ) attr(:"phx-click", :any, doc: """ Phoenix click function. Overrides the default toggle function. """ ) attr(:"phx-target", :any) attr(:"aria-label", :string) attr(:rest, :any, doc: """ Additional HTML attributes added to the item element. """ ) end end end # Dialog, drawer and menu specific defmacro is_show(the_element, component_tag) do quote do attr :is_show, :boolean, default: false, doc: """ Sets the display state of {the_element}. Control conditional display by using Phoenix's `:if` attribute. Example: ``` <{component_tag} is_show :if={@live_action in [:new, :edit]}> ... ``` """ |> String.replace("{the_element}", unquote(the_element)) |> String.replace("{component_tag}", unquote(component_tag)) end end defmacro show_state(the_element) do quote do attr :show_state, :string, values: ~w(default onset hold), default: "default", doc: """ Use when {the_element} is already displayed, and should be persisted when navigating to another LiveViews (for example to hide {the_element} with a transition after having navigated to a new route). This method does require that {the_element} is available on the other LiveView page, so it is best suited for "global" components such as navigation panels and app header menus. Use together with `is_show`. Values: - "default": No change. - "onset": Preparation for the "hold" state. Removes the "phx-remove" attribute so that navigating away doesn't cause a close transition. - "hold": Removes the "phx-remove" attribute as well as opening transitions and first focus. """ |> String.replace("{the_element}", unquote(the_element)) end end defmacro is_show_on_mount(the_element, component_tag) do quote do attr(:is_show_on_mount, :boolean, default: false, doc: """ Displays {the_element} on mount without fade-in transition. Control conditional display by using Phoenix's `:if` attribute. Example: ``` <{component_tag} is_show is_show_on_mount :if={@live_action in [:new, :edit]}> ... ``` """ |> String.replace("{the_element}", unquote(the_element)) |> String.replace("{component_tag}", unquote(component_tag)) ) end end defmacro on_cancel(the_element) do quote do attr :on_cancel, JS, default: nil, doc: """ `Phoenix.LiveView.JS` command to configure the closing/cancel event of {the_element}, for example: `on_cancel={JS.navigate(~p"/posts")}`. """ |> String.replace("{the_element}", unquote(the_element)) end end defmacro transition_duration(the_element, default_value) do quote do attr :transition_duration, :integer, default: unquote(default_value), doc: """ The number of milliseconds to fade-in/out {the_element}. Adds a CSS style attribute to {the_element} HTML. """ |> String.replace("{the_element}", unquote(the_element)) end end # Dialog and drawer specific defmacro is_modal(the_element) do quote do attr :is_modal, :boolean, default: false, doc: """ Sets modal behavior: {the_element} can only be closed with Escape or by clicking a close button. """ |> String.replace("{the_element}", unquote(the_element)) end end defmacro is_escapable do quote do attr :is_escapable, :boolean, default: true, doc: """ Closes the content when the Escape key is pressed. Set to false to prevent this. """ end end defmacro focus_after_opening_selector(the_element) do quote do attr :focus_after_opening_selector, :string, default: nil, doc: """ By default, the first interactive element gets focus after opening {the_element}. Use to set focus to a different element after opening. Pass the element selector. """ |> String.replace("{the_element}", unquote(the_element)) end end defmacro focus_after_closing_selector(the_element) do quote do attr :focus_after_closing_selector, :string, default: nil, doc: """ Returns focus to the specified element after closing {the_element}. Pass the element selector. Improve accessibility by implementing this [ARIA Dialog Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/). """ |> String.replace("{the_element}", unquote(the_element)) end end defmacro status_callback_selector(the_element) do quote do attr :status_callback_selector, :string, default: nil, doc: """ Receiver to get status callback events. Events are passed from the Prompt hook using `pushEventTo`. Pass the HTML selector of the receiver of the LiveComponent or LiveView the element is defined in. The event sends the object named "primer_live:prompt" with payload: ``` %{ "selector" => "", # callback selector "elementId" => "", # {the_element} id "status" => "" # possible values: "opening", "opened", "closing", "closed" } ``` """ |> String.replace("{the_element}", unquote(the_element)) end end end