Repository navigation
Fix focus trapping, className updates, and toast lifetimes (0.6.0) - #7
Merged
Merged
Conversation
Focus detection returned targets that cannot actually receive focus. A
dialog whose form began with a hidden input, such as a CSRF token, focused
that input, which left document.activeElement on <body> so the trap never
engaged. Hidden inputs and anything inside a [hidden], [inert], or
aria-hidden subtree are now excluded, and summary, iframe, media, and
contenteditable targets are recognised.
update({ className }) split the class string without dropping empty tokens,
so a padded or whitespace-only value made classList throw a SyntaxError.
toast() passed its duration straight to setTimeout, which coerces 0 and
Infinity to 0 and dismissed those toasts immediately instead of keeping
them until dismissed. Its auto-dismiss timer also leaked when the toast was
removed through an action button, and the region name was hardcoded English.
Also fixes the dialog stack test reset leaving the body scroll locked, reads
the test-time version from package.json so it cannot drift from the build,
pins generated API reports to LF, and refreshes dev dependencies to clear
all reported advisories.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
|
Important Review available on request
Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
cmm-cmm
marked this pull request as ready for review
August 16, 2026 09:09
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Audit of the whole project followed by fixes for the real defects it surfaced, then a
0.6.0version bump via Changesets.The baseline was already green (
npm run validatepassed, 155 tests), so this focuses on bugs the existing suite did not cover.Bug fixes
getFocusableElementsmatchedinput:not([disabled]), which includes<input type="hidden">. A dialog whose form starts with a hidden field — a CSRF token, for example — focused that input, sodocument.activeElementstayed on<body>and focus escaped the dialog entirely. Hidden inputs and anything inside a[hidden],[inert], oraria-hidden="true"subtree are now excluded.summary,iframe,audio[controls],video[controls], andcontenteditabletargets are now recognised. Detection stays attribute-based rather than layout-based so it behaves identically under jsdom.update({ className })threw. The class string was split without dropping empty tokens, so a padded, empty, or whitespace-only value reachedclassListand raisedSyntaxError: The token provided must not be empty.durationwent straight tosetTimeout, which coerces0andInfinityto0, so those toasts were removed on the next tick instead of waiting for an explicit dismiss. Both now mean "keep until dismissed".notificationsentry insetLabels().resetForTests()left the body scroll locked, leaking lock state across tests.Maintenance
vitest.config.tshardcoded__FORGEDIALOG_VERSION__as'0.5.0'while tsup read it frompackage.json; it now readspackage.jsontoo, so the version cannot drift after a bump.api:updateproduced ~1100-line phantom diffs. Reports are now pinned to LF in bothapi-extractor.jsonandscripts/check-subpath-apis.mjs, plus a.gitattributesnormalizing the repo.npm audit fix— 5 advisories (1 moderate, 4 high, all transitive dev dependencies) down to 0. Lockfile only; no dependency ranges changed.Release
changeset versionbumps0.5.0→0.6.0(minor: new optionalDialogLabels.notifications, plus the toast duration behavior change). The generated CHANGELOG entry was reformatted to match the flat bullet style used by previous releases.Test plan
npm run validatepasses end to end (typecheck, lint, coverage, size budgets, tree-shaking, publint/ATTW, API reports, subpath APIs, consumer builds, CSP, tarball size)npm test— 162 tests pass, up from 155; coverage 91.03% → 91.75% statements<body>, hidden/inert/aria-hidden subtrees, the newly recognised focusable types, theclassListSyntaxError, persistent toast durations, auto-dismiss plus action-button timer cleanup, and the localized region labelnpx playwright test --project=chromium— 11 passed, 1 skipped (mobile-only), including the Axe WCAG A/AA check and the focus-trap specs, run against the pre-installed Chromiumnpm audit— 0 vulnerabilitiesNote:
npm run test:e2ecannot run unmodified in this environment — the pinned@playwright/testexpects browser build 1228 while only 1194 is installed, and downloading browsers is disabled here. The suite was run against the pre-installed Chromium via anexecutablePathoverride; CI installs its own browsers and is unaffected.🤖 Generated with Claude Code
https://claude.ai/code/session_01MtJ3nDatGiv7dHjvZL1uZ4
Generated by Claude Code