From 4b3ea836bdf01c181183b19c591863ec017b6a7d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 6 Aug 2026 12:59:18 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Add=20tooltips=20expl?= =?UTF-8?q?aining=20disabled=20button=20states?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wraps disabled primary action buttons in layout-preserving spans with `title` attributes to explain why they are disabled, improving accessibility and reducing user friction. Updates button classes to allow pointer events to pass through to the wrappers. Co-authored-by: jspann21 <179991454+jspann21@users.noreply.github.com> --- .jules/palette.md | 3 ++ .../library/components/MatchPreviewModal.tsx | 39 +++++++++++-------- .../components/UnresolvedFilesSection.tsx | 19 +++++---- verification/test.html | 19 +++++++++ verification/verify.py | 20 ++++++++++ 5 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 verification/test.html create mode 100644 verification/verify.py diff --git a/.jules/palette.md b/.jules/palette.md index e69de29..69ac6c5 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -0,0 +1,3 @@ +## 2024-05-24 - Safely Display Tooltips on Disabled Buttons +**Learning:** Native HTML `title` tooltips and `cursor-not-allowed` styles are suppressed on `button` elements that have the native `disabled` attribute because disabled elements do not emit pointer events in most browsers. +**Action:** When adding tooltips to disabled elements, wrap the element in a layout-preserving container (like `` or `inline-flex`), apply the `title` and `cursor-not-allowed` logic to the wrapper, and use `disabled:pointer-events-none` on the inner button itself so pointer events pass through to the wrapper. diff --git a/src/features/library/components/MatchPreviewModal.tsx b/src/features/library/components/MatchPreviewModal.tsx index 78f0d0d..5f02bb4 100644 --- a/src/features/library/components/MatchPreviewModal.tsx +++ b/src/features/library/components/MatchPreviewModal.tsx @@ -246,24 +246,29 @@ export function MatchPreviewModal({ preview, onConfirm, onClose, onConfirmed }: Cancel {!noCandidates && ( - + + )} diff --git a/src/features/library/components/UnresolvedFilesSection.tsx b/src/features/library/components/UnresolvedFilesSection.tsx index 8f616e6..723a3ec 100644 --- a/src/features/library/components/UnresolvedFilesSection.tsx +++ b/src/features/library/components/UnresolvedFilesSection.tsx @@ -165,14 +165,19 @@ export function UnresolvedFilesSection({ ) : null} - + + diff --git a/verification/test.html b/verification/test.html new file mode 100644 index 0000000..a397ed3 --- /dev/null +++ b/verification/test.html @@ -0,0 +1,19 @@ + + +
+ + + + + + + + + + + + diff --git a/verification/verify.py b/verification/verify.py new file mode 100644 index 0000000..403a074 --- /dev/null +++ b/verification/verify.py @@ -0,0 +1,20 @@ +from playwright.sync_api import sync_playwright + +with sync_playwright() as p: + browser = p.chromium.launch(headless=True) + page = browser.new_page() + page.goto("file:///app/verification/test.html") + page.wait_for_timeout(1000) + page.screenshot(path="/home/jules/verification/screenshot.png") + + # Hover over Match All button wrapper + page.locator("span[title='No unresolved files to match']").hover(force=True) + page.wait_for_timeout(500) + page.screenshot(path="/home/jules/verification/match_all_hover.png") + + # Hover over Approve Match button wrapper + page.locator("span[title='Select a candidate to approve']").hover(force=True) + page.wait_for_timeout(500) + page.screenshot(path="/home/jules/verification/approve_match_hover.png") + + browser.close()