Expected Outcome
Use component helpers with inner blocks, just as we can with <.svelte .../>.
Issue
I added use LiveSvelte.Components to html_helpers in lib/myapp_web.ex:
defp html_helpers do
quote do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
import MyAppWeb.CoreComponents
import MyAppWeb.Gettext
import LiveSvelte
use LiveSvelte.Components # <--- added this
# Shortcut for generating JS commands
alias Phoenix.LiveView.JS
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end
The generated component function fails to render the inner block when passing slot content to the LiveSvelte.svelte component, as it is not picked up in LiveSvelte.Slots.filter_slots_from_assigns/1.
I did some investigation and inspected the assigns:
defmodule LiveSvelte do
# ...
def svelte(assigns) do
init = assigns.__changed__ == nil
dead = assigns.socket == nil or not LiveView.connected?(assigns.socket)
IO.inspect(assigns)
# ...
With a test component HelloWorld.svelte:
Rendering with <.HelloWorld /> in our markup we get the following assigns:
%{
name: "HelloWorld",
socket: nil,
props: %{},
__changed__: nil,
__given__: %{
name: "HelloWorld",
socket: nil,
props: %{},
__changed__: nil,
ssr: true,
class: nil
},
ssr: true,
class: nil,
inner_block: [],
live_json_props: %{}
}
Rendering with <.svelte name="HelloWorld">Foo</.svelte> with a block we get working slot/assigns:
%{
name: "HelloWorld",
socket: nil,
props: %{},
__changed__: nil,
__given__: %{
name: "HelloWorld",
__changed__: nil,
inner_block: [
%{
inner_block: #Function<6.109048978/2 in MyAppWeb.PageHTML.home/1>,
__slot__: :inner_block
}
]
},
ssr: true,
class: nil,
inner_block: [
%{
inner_block: #Function<6.109048978/2 in MyAppWeb.PageHTML.home/1>,
__slot__: :inner_block
}
],
live_json_props: %{}
}
Rendering with <.HelloWorld>Foo</.HelloWorld> the generated function component we get broken assigns with the slot content nested on props:
%{
name: "HelloWorld",
socket: nil,
props: %{
inner_block: [
%{
inner_block: #Function<8.96579134/2 in MyAppWeb.PageHTML.home/1>,
__slot__: :inner_block
}
]
},
__changed__: nil,
__given__: %{
name: "HelloWorld",
socket: nil,
props: %{
inner_block: [
%{
inner_block: #Function<8.96579134/2 in MyAppWeb.PageHTML.home/1>,
__slot__: :inner_block
}
]
},
__changed__: nil,
ssr: true,
class: nil
},
ssr: true,
class: nil,
inner_block: [],
live_json_props: %{}
}
I also discovered that Phoenix actually doesn't let one dynamically create components with attrs or slots, raising an error when attempting to add an inner_block slot on the component generator:
slot(:inner_block, required: false)
could not define slots for function CounterExample/1. Components cannot be dynamically defined or have default arguments
What can we do?
It seems the obvious way forward is for LiveSvelte.Slots to also detect slots on the props assign in its filtering.
Did you have any further insights? Is there a better way to dynamically create the component functions that is more aligned with how phoenix components work?
Expected Outcome
Use component helpers with inner blocks, just as we can with
<.svelte .../>.Issue
I added
use LiveSvelte.Componentstohtml_helpersinlib/myapp_web.ex:The generated component function fails to render the inner block when passing slot content to the
LiveSvelte.sveltecomponent, as it is not picked up inLiveSvelte.Slots.filter_slots_from_assigns/1.I did some investigation and inspected the assigns:
With a test component
HelloWorld.svelte:Rendering with
<.HelloWorld />in our markup we get the following assigns:Rendering with
<.svelte name="HelloWorld">Foo</.svelte>with a block we get working slot/assigns:Rendering with
<.HelloWorld>Foo</.HelloWorld>the generated function component we get broken assigns with the slot content nested onprops:I also discovered that Phoenix actually doesn't let one dynamically create components with attrs or slots, raising an error when attempting to add an inner_block slot on the component generator:
What can we do?
It seems the obvious way forward is for
LiveSvelte.Slotsto also detect slots on thepropsassign in its filtering.Did you have any further insights? Is there a better way to dynamically create the component functions that is more aligned with how phoenix components work?