diff --git a/assets/css/app.css b/assets/css/app.css index 04d887f..094c030 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -521,4 +521,26 @@ display: none !important; } +/* ============================================ + WCAG 1.4.3: Primary button contrast (AA) + ============================================ */ + +/* Override DaisyUI theme --color-primary-content so text on btn-primary (brand) + meets 4.5:1. In DevTools: inspect .btn-primary, check computed --color-primary + and --color-primary-content; verify contrast at https://webaim.org/resources/contrastchecker/ */ + +/* Light theme: primary is orange (brand); primary-content must be dark. */ +[data-theme="light"] { + --color-primary-content: oklch(0.18 0.02 47); + --color-error: oklch(55% 0.253 17.585); + --color-error-content: oklch(98% 0 0); +} + +/* Dark theme: primary is purple; ensure content is light and meets 4.5:1. */ +[data-theme="dark"] { + --color-primary-content: oklch(0.97 0.02 277); + --color-error: oklch(55% 0.253 17.585); + --color-error-content: oklch(98% 0 0); +} + /* This file is for your main application CSS */ diff --git a/lib/mv_web/components/core_components.ex b/lib/mv_web/components/core_components.ex index 1e90fd1..963c868 100644 --- a/lib/mv_web/components/core_components.ex +++ b/lib/mv_web/components/core_components.ex @@ -31,6 +31,21 @@ defmodule MvWeb.CoreComponents do alias Phoenix.LiveView.JS + # WCAG 2.4.7 / 2.4.11: Shared focus ring for buttons and dropdown (trigger + items) + @button_focus_classes [ + "focus-visible:outline-none", + "focus-visible:ring-2", + "focus-visible:ring-offset-2", + "focus-visible:ring-offset-base-100", + "focus-visible:ring-base-content/60" + ] + + @doc """ + Returns the shared focus ring class list for buttons and dropdown items (WCAG 2.4.7). + Use when building custom dropdown item buttons so they match <.button> and dropdown trigger. + """ + def button_focus_classes, do: @button_focus_classes + @doc """ Renders flash notices. @@ -147,13 +162,16 @@ defmodule MvWeb.CoreComponents do size_class = size_classes[size] btn_class = [base_class, size_class] |> Enum.reject(&(&1 == "")) |> Enum.join(" ") - assigns = assign(assigns, :btn_class, btn_class) + assigns = + assigns + |> assign(:btn_class, btn_class) + |> assign(:button_focus_classes, @button_focus_classes) if rest[:href] || rest[:navigate] || rest[:patch] do link_class = if assigns[:disabled], - do: ["btn", btn_class, "btn-disabled"], - else: ["btn", btn_class] + do: ["btn", btn_class, "btn-disabled"] ++ @button_focus_classes, + else: ["btn", btn_class] ++ @button_focus_classes link_attrs = if assigns[:disabled] do @@ -176,7 +194,11 @@ defmodule MvWeb.CoreComponents do """ else ~H""" - """ @@ -360,7 +382,11 @@ defmodule MvWeb.CoreComponents do def dropdown_menu(assigns) do menu_testid = assigns.menu_testid || "#{assigns.testid}-menu" - assigns = assign(assigns, :menu_testid, menu_testid) + + assigns = + assigns + |> assign(:menu_testid, menu_testid) + |> assign(:button_focus_classes, @button_focus_classes) ~H"""
Kernel.++(["focus-visible:ring-inset"]) + |> Enum.join(" ") + + "flex items-center gap-2 px-2 py-1 rounded cursor-pointer hover:bg-base-200 w-full text-left #{focus}" + end + @impl true def mount(socket) do {:ok, assign(socket, :open, false)} @@ -59,7 +69,7 @@ defmodule MvWeb.Components.ExportDropdown do