From da77615456ee05d7146c2b163119fb2329a23750 Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Mon, 24 Oct 2022 12:59:29 +0300 Subject: [PATCH] some live_view plays --- .gitignore | 1 + README.md | 2 +- lib/moon/components/select/dropdown/icon.ex | 2 +- lib/moon/helpers/surface_render.ex | 38 +++++++++++++----- lib/moon/render_helpers.ex | 35 ----------------- lib/moon_web.ex | 8 ++++ lib/moon_web/components/left_menu.ex | 2 +- lib/moon_web/components/sidebar_link.ex | 4 +- .../components/started/for_developer.ex | 2 +- lib/moon_web/pages/test/live_page.ex | 39 +++++++++++++++++++ lib/moon_web/pages/usage_page.ex | 2 +- lib/moon_web/router.ex | 1 + 12 files changed, 85 insertions(+), 51 deletions(-) delete mode 100644 lib/moon/render_helpers.ex create mode 100644 lib/moon_web/pages/test/live_page.ex diff --git a/.gitignore b/.gitignore index 6d3b69ad6..086bbca51 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ node_modules #iDEA *.iml /.idea +/.vscode diff --git a/README.md b/README.md index 3a4c8b223..9fccc6737 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ If `./run-locally-dev.sh` is not working, try the following steps: `asdf plugin add nodejs` 2. Run `asdf install`. This will install all the tool versions specified in the _.tool_versions_ file Or you can install each tool version manually by typing: - `asdf install erlang` # and follow https://github.com/asdf-vm/asdf-erlang#asdf-erlang on fail (e.g. `export KERL_CONFIGURE_OPTIONS="--disable-debug --without-javac"`) + `asdf install erlang` # and follow https://github.com/asdf-vm/asdf-erlang#asdf-erlang on fail (e.g. `export KERL_CONFIGURE_OPTIONS="--without-wx --without-javac"`) `asdf install elixir` `asdf install nodejs` diff --git a/lib/moon/components/select/dropdown/icon.ex b/lib/moon/components/select/dropdown/icon.ex index 27de59a58..3d1d64692 100644 --- a/lib/moon/components/select/dropdown/icon.ex +++ b/lib/moon/components/select/dropdown/icon.ex @@ -14,7 +14,7 @@ defmodule Moon.Components.Select.Dropdown.Icon do ~F"""
- {Moon.RenderHelpers.render_component(module, props)} + {Moon.Helpers.SurfaceRender.surface_component(props |> Map.put(:module, module))}
""" end diff --git a/lib/moon/helpers/surface_render.ex b/lib/moon/helpers/surface_render.ex index 70f69f3ff..0f1cca05d 100644 --- a/lib/moon/helpers/surface_render.ex +++ b/lib/moon/helpers/surface_render.ex @@ -22,25 +22,31 @@ defmodule Moon.Helpers.SurfaceRender do defp transform_slots(props), do: props - defp render_stateless_component(props = %{module: module}) do + @doc "used for rendering 'dead'/stateless Surface componet" + def surface_component(module, props) do component( &module.render/1, - module - |> get_default_props() - |> Map.merge(props |> Map.delete(:module) |> transform_slots()) + module |> get_default_props() |> Map.merge(props |> transform_slots()) ) end - defp render_stateful_component(props = %{module: module}) do + def surface_component(props = %{module: module}), + do: surface_component(module, props |> Map.delete(:module)) + + @doc "used for rendering live/stateful Surface componet" + def surface_live_component(props = %{module: module}) do module |> get_default_props() |> Map.merge(props |> transform_slots()) |> live_component() end + def surface_live_component(module, props), + do: surface_live_component(Map.put(props, :module, module)) + defp get_render_function(module) do %{kind: :component} = module.__live__() - &render_stateful_component/1 + &surface_live_component/1 rescue [UndefinedFunctionError, MatchError] -> - &render_stateless_component/1 + &surface_component/1 end @doc """ @@ -49,9 +55,23 @@ defmodule Moon.Helpers.SurfaceRender do Please note that only limited functional is supported, e.g. contexts and named slots are out of scope, sorry. """ - def render_surface_component(props = %{module: module}) do + def surface(props = %{module: module}) do get_render_function(module).(props) end - defdelegate surface(props), to: __MODULE__, as: :render_surface_component + # TODO: remove this dirty hack & make a PR to liveview if bug still exists in newer versions + # refer this bug report - https://github.com/phoenixframework/phoenix_live_view/issues/1656 + # looks like phoenix_live_view v0.17.6 cant nested components with the same tag, like + # <.surface module={A}><.surface ...> + # but still can handle + # <.surface0 module={A}><.surface1 ...> ... + # + # Block below works the same as: + # defdelegate surface0(props), to: __MODULE__, as: :render_surface_component + # defdelegate surface1(props), to: __MODULE__, as: :render_surface_component + # ... + # defdelegate surface99(props), to: __MODULE__, as: :render_surface_component + Enum.each(0..99, fn x -> + defdelegate unquote(:"surface#{x}")(props), to: __MODULE__, as: :surface + end) end diff --git a/lib/moon/render_helpers.ex b/lib/moon/render_helpers.ex deleted file mode 100644 index 60ac601e5..000000000 --- a/lib/moon/render_helpers.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Moon.RenderHelpers do - @moduledoc false - - def get_default_props(module) do - Enum.reduce(module.__props__(), %{}, fn - %{name: name, opts: opts, type: type}, acc -> - value = Keyword.get(opts, :values) - - value = - if type == :string and not is_nil(value) do - Enum.join(value, " ") - else - value - end - - Map.put(acc, name, value) - end) - end - - def render_component(module, custom_props) do - default_props = Moon.RenderHelpers.get_default_props(module) - use_props = Map.merge(default_props, custom_props) - - Phoenix.LiveView.Helpers.component(&module.render/1, use_props) - end - - def render_live_component(module, custom_props) do - default_props = Moon.RenderHelpers.get_default_props(module) - use_props = Map.merge(default_props, custom_props) - - assigns = Map.merge(use_props, %{module: module}) - - Phoenix.LiveView.Helpers.live_component(assigns) - end -end diff --git a/lib/moon_web.ex b/lib/moon_web.ex index 522158520..c1e60c089 100644 --- a/lib/moon_web.ex +++ b/lib/moon_web.ex @@ -50,6 +50,14 @@ defmodule MoonWeb do end end + def live_view_only do + quote do + use Phoenix.LiveView, layout: {MoonWeb.LayoutView, "live.html"} + + unquote(view_helpers()) + end + end + def stateless_component do quote do use Moon.StatelessComponent diff --git a/lib/moon_web/components/left_menu.ex b/lib/moon_web/components/left_menu.ex index 3226288c0..ba8e3e123 100644 --- a/lib/moon_web/components/left_menu.ex +++ b/lib/moon_web/components/left_menu.ex @@ -42,7 +42,7 @@ defmodule MoonWeb.Components.LeftMenu do <:menu>