defmodule LiveSvelte do @moduledoc ~S''' ## Examples ### LiveView defmodule App.SvelteLive do use App, :live_view def render(assigns) do ~H""" <.live_component module={LiveSvelte} id="Example" name="Example" props={%{items: @items, i: @i, showItems: @show_items}} /> """ end def handle_event("add_item", %{"name" => name}, socket) do socket = socket |> assign(:items, socket.assigns.items ++ [name]) |> assign(:i, length(socket.assigns.items) + 1) |> assign(:show_items, true) {:noreply, socket} end def mount(_params, _session, socket) do {:ok, socket |> assign(:items, ["One", "Two", "Three", "Four", "Five"]) |> assign(:i, 3) |> assign(:show_items, true)} end end ### Svelte Component
{#if showItems}
{#each items.slice(0, i) as item}
{item}
{/each}
{/if} ''' use Phoenix.LiveComponent import Phoenix.HTML attr(:props, :map, default: %{}) attr(:name, :string) attr(:rendered, :boolean, default: false) def render(assigns) do ~H"""
<%!-- TODO: This can return things like which should be in the head --%> <%!-- <script><%= raw(@ssr_render["head"]) %></script> --%> <style><%= raw(@ssr_render["css"]["code"]) %></style> <div id={id(@name)} data-name={@name} data-props={json(@props)} phx-update="ignore" phx-hook="SvelteComponent" > <%= raw(@ssr_render["html"]) %> </div> </div> """ end def update(assigns, socket) do # Making sure we only render once ssr_code = unless connected?(socket) do ssr_render(assigns.name, assigns[:props]) end socket = socket |> assign(assigns) |> assign(:ssr_render, ssr_code) {:ok, socket} end def ssr_render(name, props \\ %{}) do NodeJS.call!({"svelte/render", "render"}, [name, props]) end defp json(props) do props |> Jason.encode() |> case do {:ok, encoded} -> encoded {:error, _} -> "" end end defp id(name), do: "#{name}-#{System.unique_integer([:positive])}" end