From 5a951adb7c4987f64fb66a0cb7baf191b4c49e7f Mon Sep 17 00:00:00 2001 From: thiagomajesk Date: Tue, 21 Mar 2023 23:37:59 -0300 Subject: [PATCH 1/3] WIP --- lib/swish/dialog.ex | 59 +++++++++++++++------------------ lib/swish/dialog/transitions.ex | 7 ++++ lib/swish/el.ex | 17 ++++++++++ lib/swish/js.ex | 30 +++++++++++------ 4 files changed, 69 insertions(+), 44 deletions(-) create mode 100644 lib/swish/dialog/transitions.ex create mode 100644 lib/swish/el.ex diff --git a/lib/swish/dialog.ex b/lib/swish/dialog.ex index c027411..774e45e 100644 --- a/lib/swish/dialog.ex +++ b/lib/swish/dialog.ex @@ -1,8 +1,3 @@ -defmodule Swish.Dialog.Transitions do - @moduledoc false - defstruct [:show_content, :hide_content, :show_backdrop, :hide_backdrop] -end - defmodule Swish.Dialog do @moduledoc """ A dialog is a window overlaid on either the primary window or another dialog window. @@ -55,25 +50,23 @@ defmodule Swish.Dialog do alias Phoenix.LiveView.JS @doc false - def new() do + def new(attrs \\ %{}) do js_module = Swish.JS.dynamic!() - dialog_id = System.unique_integer([:positive, :monotonic]) - portal_id = System.unique_integer() %Dialog{ - id: "dialog-#{dialog_id}", - portal_id: "portal-#{portal_id}", + id: attrs[:id] || Swish.EL.new_id("dialog"), + open: attrs[:open] || false, + static: attrs[:static] || false, + open_delay: attrs[:open_delay] || 200, + close_delay: attrs[:close_delay] || 200, + portal_id: Swish.EL.new_id("portal"), js_show: Function.capture(js_module, :show_dialog, 2), js_hide: Function.capture(js_module, :hide_dialog, 2), - open: false, - static: false, - open_delay: 200, - close_delay: 200, - transitions: %Dialog.Transitions{} + transitions: attrs[:transitions] || %Dialog.Transitions{} } end - attr(:id, :string, required: false) + attr(:id, :string, default: nil) attr(:open, :boolean, default: false) attr(:static, :boolean, default: false) attr(:open_delay, :integer, default: 200) @@ -88,14 +81,14 @@ defmodule Swish.Dialog do def root(assigns) do assigns = assign_new(assigns, :dialog, fn -> - %{ - Dialog.new() - | open: assigns.open, - static: assigns.static, - open_delay: assigns.open_delay, - close_delay: assigns.close_delay, - transitions: assigns.transitions - } + Dialog.new(%{ + id: assigns.id, + open: assigns.open, + static: assigns.static, + open_delay: assigns.open_delay, + close_delay: assigns.close_delay, + transitions: assigns.transitions + }) end) ~H""" @@ -127,7 +120,7 @@ defmodule Swish.Dialog do attr(:rest, :global) def backdrop(assigns) do - assigns = assign(assigns, id: "#{assigns.dialog.id}-backdrop") + assigns = assign(assigns, id: Swish.EL.suffix_id(assigns.dialog, "backdrop")) ~H"""
"Close", - "phx-click" => hide(assigns.dialog), - "id" => "#{assigns.dialog.id}-close" + aria_label: "Close", + phx_click: hide(assigns.dialog), + id: Swish.EL.suffix_id(assigns.dialog, "close") }) ~H""" @@ -163,7 +156,7 @@ defmodule Swish.Dialog do slot(:inner_block, required: true) def content(assigns) do - assigns = assign(assigns, id: "#{assigns.dialog.id}-content") + assigns = assign(assigns, id: Swish.EL.suffix_id(assigns.dialog, "content")) ~H""" <.focus_wrap @@ -172,8 +165,8 @@ defmodule Swish.Dialog do data-hide={unless @dialog.static, do: hide(@dialog)} phx-click-away={JS.exec("data-hide")} phx-window-keydown={JS.exec("data-hide")} - aria-labelledby={"#{@dialog.id}-title"} - aria-describedby={"#{@dialog.id}-description"} + aria-labelledby={Swish.EL.suffix_id(@dialog, "title")} + aria-describedby={Swish.EL.suffix_id(@dialog, "description")} data-state={open_to_state(@dialog)} role="dialog" aria-modal="true" @@ -192,7 +185,7 @@ defmodule Swish.Dialog do slot(:inner_block, required: true) def title(assigns) do - assigns = assign(assigns, id: "#{assigns.dialog.id}-title") + assigns = assign(assigns, id: Swish.EL.suffix_id(assigns.dialog, "title")) ~H""" <.dynamic_tag id={@id} name={@as} {@rest}> @@ -207,7 +200,7 @@ defmodule Swish.Dialog do slot(:inner_block, required: true) def description(assigns) do - assigns = assign(assigns, id: "#{assigns.dialog.id}-description") + assigns = assign(assigns, id: Swish.EL.suffix_id(assigns.dialog, "description")) ~H""" <.dynamic_tag id={@id} name={@as} {@rest}> diff --git a/lib/swish/dialog/transitions.ex b/lib/swish/dialog/transitions.ex new file mode 100644 index 0000000..c190559 --- /dev/null +++ b/lib/swish/dialog/transitions.ex @@ -0,0 +1,7 @@ +defmodule Swish.Dialog.Transitions do + @moduledoc """ + Describes the available transitions for a dialog. + """ + + defstruct [:show_content, :hide_content, :show_backdrop, :hide_backdrop] +end diff --git a/lib/swish/el.ex b/lib/swish/el.ex new file mode 100644 index 0000000..18cd1a4 --- /dev/null +++ b/lib/swish/el.ex @@ -0,0 +1,17 @@ +defmodule Swish.EL do + @moduledoc false + + def new_id(prefix, escaped \\ false) + def new_id(prefix, true), do: "##{prefix}-#{System.unique_integer([:positive])}" + def new_id(prefix, false), do: "#{prefix}-#{System.unique_integer([:positive])}" + + def get_id(el, escaped \\ false) + def get_id(%{id: id}, true), do: "##{id}" + def get_id(%{id: id}, false), do: "#{id}" + + def suffix_id(el, suffix, escaped \\ false) + def suffix_id(%{id: id}, suffix, true), do: "##{id}-#{suffix}" + def suffix_id(%{id: id}, suffix, false), do: "#{id}-#{suffix}" + + def event(name), do: "swish:#{name}" +end diff --git a/lib/swish/js.ex b/lib/swish/js.ex index 20baa4a..4b50869 100644 --- a/lib/swish/js.ex +++ b/lib/swish/js.ex @@ -21,26 +21,34 @@ defmodule Swish.JS do @behaviour Swish.JS def show_dialog(js \\ %JS{}, %Swish.Dialog{} = dialog) do + trigger_target = Swish.EL.suffix_id(dialog, "trigger", true) + backdrop_target = Swish.EL.suffix_id(dialog, "backdrop", true) + content_target = Swish.EL.suffix_id(dialog, "content", true) + js |> JS.dispatch("portal:open", to: "##{dialog.portal_id}") - |> JS.set_attribute({"data-state", "open"}, to: "##{dialog.id}-trigger") - |> JS.set_attribute({"data-state", "open"}, to: "##{dialog.id}-backdrop") - |> JS.set_attribute({"data-state", "open"}, to: "##{dialog.id}-content") - |> JS.set_attribute({"aria-expanded", "true"}, to: "##{dialog.id}-trigger") + |> JS.set_attribute({"data-state", "open"}, to: trigger_target) + |> JS.set_attribute({"data-state", "open"}, to: backdrop_target) + |> JS.set_attribute({"data-state", "open"}, to: content_target) + |> JS.set_attribute({"aria-expanded", "true"}, to: trigger_target) |> JS.show( - to: "##{dialog.id}-backdrop", + to: backdrop_target, transition: dialog.transitions.show_backdrop, time: dialog.open_delay ) |> JS.show( - to: "##{dialog.id}-content", + to: content_target, transition: dialog.transitions.show_content, time: dialog.open_delay ) - |> JS.focus_first(to: "##{dialog.id}-content") + |> JS.focus_first(to: content_target) end def hide_dialog(js \\ %JS{}, %Swish.Dialog{} = dialog) do + trigger_target = Swish.EL.suffix_id(dialog, "trigger", true) + backdrop_target = Swish.EL.suffix_id(dialog, "backdrop", true) + content_target = Swish.EL.suffix_id(dialog, "content", true) + js |> JS.pop_focus() |> JS.hide( @@ -53,10 +61,10 @@ defmodule Swish.JS do transition: dialog.transitions.hide_content, time: dialog.close_delay ) - |> JS.set_attribute({"data-state", "closed"}, to: "##{dialog.id}-trigger") - |> JS.set_attribute({"data-state", "closed"}, to: "##{dialog.id}-backdrop") - |> JS.set_attribute({"data-state", "closed"}, to: "##{dialog.id}-content") - |> JS.set_attribute({"aria-expanded", "false"}, to: "##{dialog.id}-trigger") + |> JS.set_attribute({"data-state", "closed"}, to: trigger_target) + |> JS.set_attribute({"data-state", "closed"}, to: backdrop_target) + |> JS.set_attribute({"data-state", "closed"}, to: content_target) + |> JS.set_attribute({"aria-expanded", "false"}, to: trigger_target) |> JS.dispatch("portal:close", to: "##{dialog.portal_id}") end From 8ac2ac7c2c4d4f5887939abd1cfd4a0488eb37b3 Mon Sep 17 00:00:00 2001 From: thiagomajesk Date: Tue, 21 Mar 2023 23:39:05 -0300 Subject: [PATCH 2/3] Remove trailing whitespaces messing up formatting --- lib/swish/dialog.ex | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/swish/dialog.ex b/lib/swish/dialog.ex index 774e45e..8e5e055 100644 --- a/lib/swish/dialog.ex +++ b/lib/swish/dialog.ex @@ -19,9 +19,9 @@ defmodule Swish.Dialog do Welcome to Swish! - Swish is a UI toolkit for busy developers + Swish is a UI toolkit for busy developers

Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.

-
+
From 1de7297b9e4d8b2fb7f901cdfecd56504b9fa565 Mon Sep 17 00:00:00 2001 From: thiagomajesk Date: Tue, 21 Mar 2023 23:42:30 -0300 Subject: [PATCH 3/3] WIP --- lib/swish/dialog.ex | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/swish/dialog.ex b/lib/swish/dialog.ex index 8e5e055..512901d 100644 --- a/lib/swish/dialog.ex +++ b/lib/swish/dialog.ex @@ -104,10 +104,10 @@ defmodule Swish.Dialog do def trigger(assigns) do assigns = assign(assigns, :attrs, %{ - "aria-haspopup" => "dialog", - "phx-click" => JS.exec("data-show", to: "##{assigns.dialog.portal_id}"), - "id" => "#{assigns.dialog.id}-trigger", - "data-state" => open_to_state(assigns.dialog) + aria_haspopup: "dialog", + phx_click: JS.exec("data-show", to: "##{assigns.dialog.portal_id}"), + id: Swish.EL.suffix_id(assigns.dialog, "trigger"), + data_state: open_to_state(assigns.dialog) }) ~H"""