Skip to content

Fix keyboard-handling regressions + regression tests (focus-trap preserved)#28

Draft
gnbm wants to merge 3 commits into
masterfrom
RegressionTests
Draft

Fix keyboard-handling regressions + regression tests (focus-trap preserved)#28
gnbm wants to merge 3 commits into
masterfrom
RegressionTests

Conversation

@gnbm

@gnbm gnbm commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes three pre-existing regressions in src/index.ts (all already on master) surfaced by failing unit tests, and adds regression tests that lock the fixed behavior. The time-picker Tab fix is implemented so it does not break the accessibility focus-trap introduced in 35997745.

Regressions fixed

  1. onKeyDown hook stopped firing for input keydowns. When input keydown handling was split into onInputKeyDown, the handler never re-fired the public onKeyDown hook, and it matched only e.key (ignoring the legacy e.keyCode). Restored the hook and made key-matching accept both. Fixes API › destroy() and API › onKeyDown closes flatpickr on Enter when allowInput set to true.
  2. Time-picker Tab navigation broke UI › time-picker focuses out onto input. See the accessibility note below.
  3. onBlur misfired onChange. For configs without altInput, valueChanged was hardcoded true, so blurring an empty, untouched input fired onChange. Restored the historical guard (selectedDates.length > 0 || _input.value.length > 0). Fixes events + hooks › onBlur › doesn't misfire.

Accessibility: focus-trap preserved

The initial fix for (2) reinstated manual JS Tab-cycling that the accessibility work (35997745) had intentionally removed. That cycling called preventDefault() + focus() and, on Tab from the last time element, moved focus to self._input — outside the calendar container — escaping the focus trap and overriding the a11y-managed native tab order.

This PR instead keeps onTimeKeydown at the accessibility-designed behavior: native tab order (all interactive elements are tabindex=0 while open) plus the focus-trap elements keep focus inside the open dialog; only Shift+Tab out of the hour element is handled in JS. The time-picker tests were realigned to assert the focus-trap model rather than the old "tab out to the input" expectation (which only failed under jsdom because jsdom does not simulate native Tab traversal).

Tests

  • All 117 unit tests pass; typecheck clean.
  • Each regression-catcher was verified to fail against the pre-fix source.
  • The time-picker leaves forward tab navigation between time elements to the browser test was verified to fail if the JS cycling is re-introduced, guarding the focus trap.

Notes for reviewers

  • No public API changes; these are behavior restorations.
  • Does not include the ROU-12898 timezone/onChange fix — this branch and ROU-12898 branch from the same master with disjoint changes and should be reconciled before merge.

gnbm added 3 commits July 7, 2026 22:48
Restores behavior dropped when input keydown handling was split out of
the shared onKeyDown into onInputKeyDown/onTimeKeydown, and fixes an
onBlur misfire predating that change:

- onInputKeyDown never called triggerEvent("onKeyDown", e), so
  user-registered onKeyDown callbacks stopped firing for keys pressed
  in the input.
- onInputKeyDown/onTimeKeydown matched only e.key, silently no-oping
  for callers that only set the legacy e.keyCode.
- onTimeKeydown only handled Shift+Tab out of the hour element; the
  original Tab-cycling across hour/minute/second/AM-PM/plugin elements
  had been commented out with no replacement.
- onBlur hardcoded valueChanged = true for configs without altInput,
  so blurring an empty, untouched input always fired onChange.
Locks the three regressions fixed in the previous commit plus the
opposite-direction behavior so a future refactor can't silently
reintroduce them:

- onKeyDown hook fires exactly once for a keydown on the input.
- ArrowDown on the input opens the calendar (e.keyCode path).
- Enter closes when allowInput is set, via e.key as well as e.keyCode.
- Time picker tabs forward through hour/minute/second/AM-PM to the input.
- onBlur still fires onChange when a value is entered without altInput
  (companion to the existing "doesn't misfire" test).

Verified each regression-catcher fails against the pre-fix source.
The earlier onTimeKeydown fix reinstated manual JS Tab-cycling across the
time elements that the accessibility work (3599774) had intentionally
removed. That cycling called preventDefault + focus() and, on Tab from the
last time element, moved focus to self._input - which lives outside the
calendar container, escaping the focus trap and overriding the a11y-managed
native tab order. This regressed keyboard navigation for all time-enabled
pickers.

Revert onTimeKeydown to the accessibility-designed behavior: native tab
order (elements are tabindex=0 while open) plus the focus-trap elements keep
focus inside the open dialog; only Shift+Tab out of the hour element is
handled in JS (back into the calendar days / altInput).

Realign the time-picker tests with the focus-trap model instead of the old
"tab out to the input" expectation, which only failed under jsdom because
jsdom does not simulate native Tab traversal:

- keeps keyboard focus trapped within the calendar (trap wrap + tabindex)
- leaves forward tab navigation between time elements to the browser
  (guards against re-introducing the JS cycling that broke the trap)
- Shift+Tab from the hour element returns focus to the calendar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant