fix(date-field): flag typed/shortcut input invalid when outside min/max or unavailable#390
Merged
Merged
Conversation
…teUnavailable
Typing a date (or landing one via a keyboard shortcut) outside the allowed
range was silently accepted — minValue/maxValue were only consulted by the
shortcut clamp, and isDateUnavailable only gated calendar selection. The field
now flags such a value invalid (aria-invalid + a built-in message) while still
emitting it through onChange, matching the calendar's behavior and react-aria's
validation contract.
- Remove the applyShortcut clamp: a shortcut target outside [min,max] is
surfaced as invalid rather than coerced to the boundary, consistent with
typing. The open-popover (calendar) path still clamps roving focus.
- Honour isDateUnavailable in field validation (DateField + DatePicker), not
just calendar selection.
- useDateFieldState now returns { isInvalid, invalidReason }; date-field.tsx
ORs it into the derived invalid state and shows a localized default message
(en/ja) that a consumer errorMessage overrides.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
interacsean
marked this pull request as ready for review
July 16, 2026 06:01
Contributor
|
/review |
Contributor
|
✅ API Design Review completed successfully! API design review complete for PR #390 — no issues found. Approved. Changes fix date validation for typed/shortcut input, correctly wire isDateUnavailable to field state, and keep new types (DateFieldInvalidReason) internal. No breaking public API surface changes. |
IzumiSy
approved these changes
Jul 16, 2026
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
Fixes a pre-existing bug (spotted in the vite example's "Future dates only" DatePicker): a date entered by typing — or landed via a keyboard shortcut — outside the allowed range was silently accepted.
minValue/maxValuewere only consulted by the shortcut clamp, andisDateUnavailableonly gated calendar selection; the typed value had no validation at all.The field now flags such a value invalid (
aria-invalidon the segments + a built-in message) while still emitting it throughonChange— matching how the calendar already behaves and Adobe React ARIA's validation contract (which flags invalid rather than clamping text entry).This is independent of the DateRangePicker work in #388 — it lives in the shared field engine (
use-date-field-state.ts) and back-fixesDateFieldandDatePicker. TheDateRangePickerinherits the same hook and will get a small wiring commit on #388.Changes
applyShortcutno longer clamps. A shortcut target (e.g.y→ 1 Jan) outside[minValue, maxValue]is now surfaced as invalid instead of being coerced to the boundary — consistent with typing. The open-popover (calendar) path still clamps roving focus, since you can't type there.isDateUnavailabledrives field validation (bothDateFieldandDatePicker), not just calendar selection — so weekends or specific blackout dates typed into the field are flagged too.useDateFieldStatereturns{ isInvalid, invalidReason }(range vs unavailable).date-field.tsxORs it into the derived invalid state and shows a localized default message (en/ja) that a consumererrorMessageoverrides.onChange— we flag, we don't block or clamp — so forms can decide what to do with it.Testing
pnpm --filter @tailor-platform/app-shell test— 1354 passing. New/updated coverage indate-field.test.tsx:minValue→ invalid + still emits (with the built-in message)isDateUnavailable) → invalidapplyShortcutout of[min,max]→ invalid, not clamped (DateField + DatePicker); the open-popover shortcut still clamps roving focus (unchanged)pnpm type-check(9/9) andpnpm lintclean.Note: keyboard-driven manual repro isn't feasible through the preview harness (the iframe won't hold focus for synthetic key events), so the behavior is verified by the RTL suite above, which drives the real key handlers via
userEvent.keyboard.Follow-up
Once this merges, #388 rebases onto it and gains a two-line wiring (pass
isDateUnavailableto each end's field state + ORisInvalidinto the range picker's derived invalid state) so the range picker's typed ends validate the same way.🤖 Generated with Claude Code