refactor(web): share member-dropdown keyboard navigation between LiveViews

This commit is contained in:
Moritz 2026-06-16 15:03:05 +02:00
parent 070d9d1fc3
commit bc1dbb1d11
3 changed files with 89 additions and 119 deletions

View file

@ -43,6 +43,7 @@ defmodule MvWeb.UserLive.Form do
alias Mv.Membership
alias Mv.Membership.Member, as: MemberResource
alias MvWeb.Helpers.MemberHelpers
alias MvWeb.Live.MemberDropdownNav
import MvWeb.LiveHelpers, only: [current_actor: 1, submit_form: 3]
import MvWeb.Authorization, only: [can?: 3]
@ -571,56 +572,8 @@ defmodule MvWeb.UserLive.Form do
end
@impl true
def handle_event("member_dropdown_keydown", %{"key" => "ArrowDown"}, socket) do
return_if_dropdown_closed(socket, fn ->
max_index = length(socket.assigns.available_members) - 1
current = socket.assigns.focused_member_index
new_index =
case current do
nil -> 0
index when index < max_index -> index + 1
_ -> current
end
{:noreply, assign(socket, focused_member_index: new_index)}
end)
end
@impl true
def handle_event("member_dropdown_keydown", %{"key" => "ArrowUp"}, socket) do
return_if_dropdown_closed(socket, fn ->
current = socket.assigns.focused_member_index
new_index =
case current do
nil -> 0
0 -> 0
index -> index - 1
end
{:noreply, assign(socket, focused_member_index: new_index)}
end)
end
@impl true
def handle_event("member_dropdown_keydown", %{"key" => "Enter"}, socket) do
return_if_dropdown_closed(socket, fn ->
select_focused_member(socket)
end)
end
@impl true
def handle_event("member_dropdown_keydown", %{"key" => "Escape"}, socket) do
return_if_dropdown_closed(socket, fn ->
{:noreply, assign(socket, show_member_dropdown: false, focused_member_index: nil)}
end)
end
@impl true
def handle_event("member_dropdown_keydown", _params, socket) do
# Ignore other keys
{:noreply, socket}
def handle_event("member_dropdown_keydown", params, socket) do
MemberDropdownNav.handle_keydown(params, socket, fn -> select_focused_member(socket) end)
end
@impl true
@ -778,17 +731,6 @@ defmodule MvWeb.UserLive.Form do
@spec notify_parent(any()) :: {module(), any()}
defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
# Helper to ignore keyboard events when dropdown is closed
@spec return_if_dropdown_closed(Phoenix.LiveView.Socket.t(), function()) ::
{:noreply, Phoenix.LiveView.Socket.t()}
defp return_if_dropdown_closed(socket, func) do
if socket.assigns.show_member_dropdown do
func.()
else
{:noreply, socket}
end
end
# Select the currently focused member from the dropdown
@spec select_focused_member(Phoenix.LiveView.Socket.t()) ::
{:noreply, Phoenix.LiveView.Socket.t()}