Does anybody know a way of “inheriting” all attrs
from a function component? So for example if I want to create a specific variant of the link
component I’d like to have all attrs which link
supports in my custom component. Right now, the only way I know is to copy them over, which is a little pain, especially if the upstream component changes.
Additionally, if I define the attrs
I also need to pass each of them manually.
Would it be possible to create a macro which you can pass an existing component which can then be “spread” (like :global
attributes) into the custom component?
# I want to inherit these from link/1
attr :navigate, :string, default: nil
attr :patch, :string, default: nil
attr :href, :any, default: nil
attr :replace, :boolean, default: false
# ...
attr :active, :boolean, default: false
attr :rest, :global, default: %{}
slot :icon
slot :inner_block
def nav_link(assigns) do
~H"""
<.link
navigate={@navigate}
patch={@patch}
href={@href}
replace={@replace}
class={[
"group flex items-center px-2 py-2 text-sm font-medium rounded-md border border-transparent",
if(@active,
do: "bg-gradient-to-b from-zinc-800 to-zinc-700 text-white border-zinc-600 shadow-lg",
else:
"text-zinc-300 hover:bg-zinc-700 hover:text-white group flex items-center px-2 py-2 text-sm font-medium rounded-md"
)
]}
{@rest}
>
<span class="text-zinc-400 group-hover:text-zinc-300 mr-3 flex-shrink-0 h-6 w-6">
<%= render_slot(@icon) %>
</span>
<%= render_slot(@inner_block) %>
</.link>
"""
end
What I’d love to have:
# somehow embed attrs from another component
attr :link_attrs, embed: &link/1
attr :active, :boolean, default: false
attr :rest, :global, default: %{}
slot :icon
slot :inner_block
def nav_link(assigns) do
~H"""
<.link
class={[
"group flex items-center px-2 py-2 text-sm font-medium rounded-md border border-transparent",
if(@active,
do: "bg-gradient-to-b from-zinc-800 to-zinc-700 text-white border-zinc-600 shadow-lg",
else:
"text-zinc-300 hover:bg-zinc-700 hover:text-white group flex items-center px-2 py-2 text-sm font-medium rounded-md"
)
]}
{@link_attrs}
{@rest}
>
<span class="text-zinc-400 group-hover:text-zinc-300 mr-3 flex-shrink-0 h-6 w-6">
<%= render_slot(@icon) %>
</span>
<%= render_slot(@inner_block) %>
</.link>
"""
end
The only thing I can think of right now, is adding an attr of :map
and include the original component attrs there. Downside is, that you won’t get any compiler warnings of incorrect attrs.
attr :link_attrs, :map, default: %{}
attr :active, :boolean, default: false
attr :rest, :global, default: %{}
slot :icon
slot :inner_block
def nav_link(assigns) do
~H"""
<.link
class={[
"group flex items-center px-2 py-2 text-sm font-medium rounded-md border border-transparent",
if(@active,
do: "bg-gradient-to-b from-zinc-800 to-zinc-700 text-white border-zinc-600 shadow-lg",
else:
"text-zinc-300 hover:bg-zinc-700 hover:text-white group flex items-center px-2 py-2 text-sm font-medium rounded-md"
)
]}
{@link_attrs}
{@rest}
>
<span class="text-zinc-400 group-hover:text-zinc-300 mr-3 flex-shrink-0 h-6 w-6">
<%= render_slot(@icon) %>
</span>
<%= render_slot(@inner_block) %>
</.link>
"""
end