feat(member): keep text selection in the overview table from opening the member
This commit is contained in:
parent
be57dcfce8
commit
24f67bea80
3 changed files with 36 additions and 0 deletions
|
|
@ -103,6 +103,29 @@ Hooks.TableRowKeydown = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RowSelectionGuard: distinguish drag-to-select-text from a plain click on the members table.
|
||||||
|
// LiveView fires the row navigation push (select_row_and_navigate) on any click. When the user
|
||||||
|
// drags across a cell to select text (e.g. an email to copy) and releases, the mouseup produces a
|
||||||
|
// non-empty text selection; in that case we swallow the click in the capture phase so navigation is
|
||||||
|
// suppressed. A plain click leaves the selection collapsed and navigates as before.
|
||||||
|
Hooks.RowSelectionGuard = {
|
||||||
|
mounted() {
|
||||||
|
this.handleClickCapture = (e) => {
|
||||||
|
const selection = window.getSelection()
|
||||||
|
if (selection && !selection.isCollapsed && selection.toString().trim() !== "") {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Capture phase so this runs before LiveView's bubbling phx-click handler.
|
||||||
|
this.el.addEventListener("click", this.handleClickCapture, true)
|
||||||
|
},
|
||||||
|
|
||||||
|
destroyed() {
|
||||||
|
this.el.removeEventListener("click", this.handleClickCapture, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// FocusRestore hook: WCAG 2.4.3 — when a modal closes, focus returns to the trigger element (e.g. "Delete member" button)
|
// FocusRestore hook: WCAG 2.4.3 — when a modal closes, focus returns to the trigger element (e.g. "Delete member" button)
|
||||||
Hooks.FocusRestore = {
|
Hooks.FocusRestore = {
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,8 @@
|
||||||
|
|
||||||
<%!-- On desktop (lg:), only the table area scrolls; header and filters stay visible. On mobile, normal flow. --%>
|
<%!-- On desktop (lg:), only the table area scrolls; header and filters stay visible. On mobile, normal flow. --%>
|
||||||
<div
|
<div
|
||||||
|
id="members-table-guard"
|
||||||
|
phx-hook="RowSelectionGuard"
|
||||||
class="lg:max-h-[calc(100vh-14rem)] lg:overflow-auto min-h-0"
|
class="lg:max-h-[calc(100vh-14rem)] lg:overflow-auto min-h-0"
|
||||||
data-testid="members-table-scroll"
|
data-testid="members-table-scroll"
|
||||||
role="region"
|
role="region"
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,17 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "drag-select vs click guard (§3.3)" do
|
||||||
|
@describetag :ui
|
||||||
|
|
||||||
|
test "members table carries the row-selection guard hook", %{conn: conn} do
|
||||||
|
conn = conn_with_oidc_user(conn)
|
||||||
|
{:ok, view, _html} = live(conn, ~p"/members")
|
||||||
|
|
||||||
|
assert has_element?(view, "[phx-hook=RowSelectionGuard][id=members-table-guard]")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "translations" do
|
describe "translations" do
|
||||||
@describetag :ui
|
@describetag :ui
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue