Hello,
After a few days of letting this aside, I’m thinking there is something very similar in my first attempt to another experiment where I implemented some kind of interpreter for Canvas operations :
defp draw_players(%Game{} = game, w, h) do
for player <- game.players do
[
:begin_path,
{:line_width, 20},
{:stroke_style, "red"},
{:arc, [w / 2, h / 2, Enum.min([w, h]) / 2 * 0.7, player.start_pos, player.end_pos]},
:stroke,
:close_path
]
end
end
Here, lists of tuples were converted to a flat list of instructions for a tiny JS runtime to consume, which produced a frame :
[0, 5, 20, 6, "red", 8, 400.0, 400.0, 280.0, 0, 0.6283185307179586, false, 2, 3, 0, 5, 20, 6, "red", 8, 400.0, 400.0, 280.0, 2.0943951023931957, 2.7227136331111543, false, 2, 3, 0, 5, 20, 6, "red", 8, 400.0, 400.0, 280.0, 4.188790204786391, 4.81710873550435, false, 2, 3, 0, 4, "white", 8, 400.0, 400.0, 10, 0, 6.283185307179586, false, 1, 3]
How you produced those tuples were up to you, and you could abstract that into higher level operations. Putting aside this canvas thing, I still think the “limited DOM access” I was talking earlier could be useful to avoid hook expansion and UI Layout logic fragmentation.
TestWeb.DOMStuff.seq_exec(
socket,
[
Ops.ignore(box_2),
Ops.get_bounding_client_rect(box_1, fn s, v -> update(s, :box_dimensions, fn _ -> v end) end),
Ops.set_height(box_2, fn s -> "#{2 * s.assigns.box_dimensions["width"]}px" end),
Ops.get_bounding_client_rect(box_2, fn s, v -> update(s, :blue_box_dimensions, fn _ -> v end) end),
Ops.un_ignore(box_2),
],
fn s -> update(s, :got_everything, fn _ -> true end) end
)}
This is fine in some way, but could also easily snowball into use-cases where the companion hook that allows for this interaction gets stateful, and the ability to store reference to elements and use them in commands Elixir-side gets added… and I think I know where that road leads.
I have another POC that allows to dynamically register Hooks which code is co-located with the Elixir code of a component, akin to Vue single file components, which could be another point of view / another take on this.
In the meantime, I’ll be wise and not use any of that, but the underlying ideas are of interest to me. Maybe LiveView does not have the goal of fully replacing interaction-heavy parts of more advanced SPAs, but people who have the joy to use LiveView and at the same time work on SPAs will try to shoehorn it into that use-case