diff --git a/CODE_GUIDELINES.md b/CODE_GUIDELINES.md index 48e2e8e..b3f1c3f 100644 --- a/CODE_GUIDELINES.md +++ b/CODE_GUIDELINES.md @@ -3016,6 +3016,8 @@ end - [ ] Tables have proper structure (th, scope, caption) - [ ] ARIA labels used for icon-only buttons - [ ] Modals/dialogs: focus moves into modal, aria-labelledby, keyboard dismiss (Escape) +- [ ] ARIA state attributes use string values `"true"` / `"false"` (not boolean), e.g. `aria-selected`, `aria-pressed`, `aria-expanded`. +- [ ] Tabs: when using `role="tablist"` / `role="tab"`, use roving tabindex (only active tab `tabindex="0"`) and ArrowLeft/ArrowRight to switch tabs. ### 8.11 Modals and Dialogs @@ -3043,7 +3045,8 @@ Use a consistent, keyboard-accessible pattern for all confirmation and form moda **Closing:** - Cancel button closes the modal (e.g. `phx-click="cancel_delete_modal"`). -- Optionally support Escape to close via `phx-window-keydown` on the LiveView/LiveComponent. +- **MUST** support Escape to close (WCAG / WAI-ARIA dialog pattern): add `phx-keydown="dialog_keydown"` on the `
<.button + id="delete-custom-field-trigger" type="button" variant="danger" phx-click="request_delete" diff --git a/lib/mv_web/live/custom_field_live/index_component.ex b/lib/mv_web/live/custom_field_live/index_component.ex index abb19df..f9dca11 100644 --- a/lib/mv_web/live/custom_field_live/index_component.ex +++ b/lib/mv_web/live/custom_field_live/index_component.ex @@ -106,6 +106,7 @@ defmodule MvWeb.CustomFieldLive.IndexComponent do class="modal modal-open" role="dialog" aria-labelledby="delete-custom-field-modal-title" + phx-keydown="dialog_keydown" >{msg}
+ <% end %> + <%= if @interval_warning do %> ++ {gettext( + "Select a membership fee type for this member. Members can only switch between types with the same interval." + )} +
{msg}
- <% end %> - <%= if @interval_warning do %> -
+ <%!-- Danger zone: same section pattern as MemberLive.Show (canonical) --%>
+ <%= if @member && can?(@current_user, :destroy, @member) do %>
+
{gettext(
- "Select a membership fee type for this member. Members can only switch between types with the same interval."
+ "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed."
)}
+ {gettext("Danger zone")}
+
+
- {gettext( - "Deleting this member cannot be undone. All related data (e.g. membership fee cycles) will be removed." - )} -
- <.button - variant="danger" - type="button" - phx-click="open_delete_modal" - data-testid="member-delete" - aria-label={ - gettext("Delete member %{name}", - name: MvWeb.Helpers.MemberHelpers.display_name(@member) - ) - } - > - <.icon name="hero-trash" class="size-4" /> - {gettext("Delete member")} - -- {gettext( - "Deleting this role cannot be undone. Users assigned to this role must be reassigned first." - )} -
- <.button - variant="danger" - phx-click="open_delete_modal" - data-testid="role-delete" - aria-label={gettext("Delete role %{name}", name: @role.name)} - > - <.icon name="hero-trash" class="size-4" /> - {gettext("Delete role")} - -