Packages
moon
2.81.1
2.90.5
retired
2.90.4
2.90.3
2.90.2
2.90.1
2.90.0
2.89.4
2.89.1
2.89.0
2.88.0
2.87.11
2.87.10
2.87.9
2.87.8
2.87.7
2.87.6
2.87.5
2.87.4
2.87.3
2.87.2
2.87.1
2.87.0
2.86.1
2.86.0
2.85.1
2.85.0
2.84.0
2.83.0
2.82.0
2.81.4
2.81.3
2.81.2
2.81.1
2.81.0
2.80.2
2.80.1
2.80.0
2.79.13
2.79.12
2.79.11
2.79.10
2.79.9
2.79.8
2.79.7
2.79.6
2.79.5
2.79.4
2.79.3
2.79.2
2.79.1
2.79.0
2.78.4
2.78.3
2.78.2
2.78.1
2.78.0
2.77.0
2.76.5
2.76.4
2.76.3
2.76.2
2.76.1
2.76.0
2.75.0
2.74.1
2.74.0
2.73.8
2.73.7
2.73.6
2.73.5
2.73.4
2.73.3
2.73.2
2.73.1
2.73.0
2.72.5
2.72.4
2.72.3
2.72.2
2.72.1
2.72.0
2.71.1
2.71.0
2.70.0
2.69.2
2.69.1
2.69.0
2.68.11
2.68.10
Components-based design system written in elixir
Current section
Files
Jump to
Current section
Files
lib/moon/helpers/moon_render.ex
defmodule Moon.Helpers.MoonRender do
@moduledoc """
Functions for rendering Moon (or Surface, either LiveView) components in HEEX/SLIM/... (not Surface) templates
"""
alias Phoenix.LiveView.{TagEngine, HTMLEngine}
import Phoenix.Component, only: [live_component: 1]
defp component(func, assigns, caller) do
module =
if function_exported?(TagEngine, :component, 3) do
# phoenix_live_view 0.18.18
TagEngine
else
# phoenix_live_view < 0.18.18
HTMLEngine
end
apply(module, :component, [func, assigns, caller])
end
defp get_default_props(module) do
Enum.reduce(module.__props__(), %{__context__: %{}}, fn
%{name: name, opts: opts}, acc ->
Map.put(acc, name, Keyword.get(opts, :default))
end)
end
defp transform_slots(
props = %{inner_block: [%{__slot__: :inner_block, inner_block: inner_block}]}
) do
props
|> Map.delete(:inner_block)
|> Map.put(:default, [%{__slot__: :default, inner_block: inner_block}])
end
defp transform_slots(props), do: props
@doc "Used for rendering stateless Surface componet"
def surface_component(module, props) do
component(
&module.render/1,
get_default_props(module) |> Map.merge(transform_slots(props)),
{__ENV__.module, __ENV__.function, __ENV__.file, __ENV__.line}
)
end
def surface_component(props = %{module: module}),
do: surface_component(module, props |> Map.delete(:module))
@doc "Used for rendering live (stateful) Surface component"
def surface_live_component(props = %{module: module}) do
get_default_props(module) |> Map.merge(transform_slots(props)) |> live_component()
end
def surface_live_component(module, props),
do: surface_live_component(Map.put(props, :module, module))
def is_live(module) do
%{kind: :component} = module.__live__()
true
rescue
[UndefinedFunctionError, MatchError] ->
false
end
defp get_render_function(module) do
cond do
!function_exported?(module, :__props__, 0) ->
&live_component/1
is_live(module) ->
&surface_live_component/1
true ->
&surface_component/1
end
end
@doc """
A function for rendering Surface components inside non-surface templates
usage: `<.moon module="Button">hit me!</.moon>`
Please note that only limited functional is supported, e.g. context get & named
slots are out of scope, sorry.
"""
def moon(props = %{module: module}) do
get_render_function(module).(props)
end
end