Skip to content

feat(DateRangeInput): add maxRangeSpan/minRangeSpan to constrain range size - #5145

Merged
cixzhang merged 1 commit into
mainfrom
feat/daterange-max-span
Aug 19, 2026
Merged

feat(DateRangeInput): add maxRangeSpan/minRangeSpan to constrain range size#5145
cixzhang merged 1 commit into
mainfrom
feat/daterange-max-span

Conversation

@freddymeta

Copy link
Copy Markdown
Contributor

Summary

DateRangeInput (and the underlying Calendar in mode="range") can constrain where dates fall (min/max, dateConstraints) but not how wide the selected range may be. There is no way to express "once the user picks a start date, the end date can't be more than a week away" — a rolling window relative to the chosen start.

This adds two props to express that:

  • maxRangeSpan?: number — the maximum number of days a range may span, counting both endpoints (maxRangeSpan={7} = a 7-day window, start + 6). Once a start is picked, days beyond that distance from it are disabled in either direction.
  • minRangeSpan?: number — the minimum span, both endpoints counted (minRangeSpan={2} forbids a single-day range). Defaults to 1.
// A reporting filter limited to a one-week window
<DateRangeInput label="Reporting period" value={v} onChange={setV} maxRangeSpan={7} />

// A stay of at least 2 and at most 30 days
<DateRangeInput label="Stay" value={v} onChange={setV} minRangeSpan={2} maxRangeSpan={30} />

Design notes

  • Config over callback. A finite, well-known option ("max N days") is a declarative prop rather than a context-aware dateConstraints closure. maxRangeSpan={7} is discoverable and reads at a glance; an anchor-relative closure is neither. Arbitrary anchor-relative rules that aren't a day-count remain out of scope by design — if a real one shows up, extending dateConstraints with the pending anchor is the future escape hatch.
  • Inclusive-day semantics, documented on both props to avoid the "7 days vs 7 nights" ambiguity. The reachable distance from the anchor is span - 1 days.
  • Selection-only. The constraint governs which days are pickable; it never rewrites a controlled value that is already wider than the cap. Surface such a value with status if you need to flag it.
  • Mechanism: the in-progress range start (already tracked internally) is threaded into useCalendarConstraints, which disables candidate days outside [anchor − (max−1), anchor + (max−1)] and inside the min band. Span constraints apply in range mode only.

Test plan

  • pnpm -F @astryxdesign/core test — Calendar, DateRangeInput, and plainDate suites pass (207 tests). New coverage:
    • Calendar caps the end date at maxRangeSpan (both directions, boundary days), enforces minRangeSpan, and does not apply span constraints in single mode.
    • DateRangeInput forwards maxRangeSpan to the calendar.
    • plainDateDiffDays unit tests (forward/backward/zero, month + year rollover, DST-safe).
  • pnpm -F @astryxdesign/core build — clean.
  • pnpm -F @astryxdesign/core typecheck — clean.
  • Docs (.doc.mjs for both components, EN + zh + dense), Storybook stories, and a changeset are included.

@vercel

vercel Bot commented Aug 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 18, 2026 1:28am

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 17, 2026
@github-actions github-actions Bot added community Authored by a community contributor (not on the eng/design team) needs:code-review High-risk change (new package/component/API) — needs human code review before merge labels Aug 17, 2026
@freddymeta
freddymeta force-pushed the feat/daterange-max-span branch from d869ab1 to eb0024a Compare August 17, 2026 11:08
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Calendar (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 1361 -
Complexity N/A Very High (138) -
DateRangeInput (@astryxdesign/core) · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 526 -
Complexity N/A Very High (66) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.8KB 1.2KB

Accessibility Audit

Status: 1 accessibility violation(s) found — 1 critical.

DateRangeInput - 1 issue(s)
  • 🔴 critical: Ensure an element's role supports its ARIA attributes
    • Rule: aria-allowed-attr · Affects 1/20 stories · Learn more
    • WCAG: 4.1.2 (Level A)

Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Aug 17, 2026
github-actions Bot added a commit that referenced this pull request Aug 17, 2026

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the grid work is solid, and I checked both maxRangeSpan boundaries in Chrome; the window is exactly right.

minRangeSpan isn't enforced yet: with minRangeSpan={2}, clicking Aug 10 twice commits a one-day range, which is the case the prop says it forbids. Once the anchor is placed the span is knowable, same as the max — so the days inside it should be disabled as end dates.

One catch to get right: with those days disabled you can't click Aug 11 to start over there. So clicking the anchor again should toggle it off and clear the selection, rather than restart — otherwise moving the start a day over is impossible.

Separately, a Last 30 days preset applies under maxRangeSpan={7}. Should a preset override the cap, or be disabled when it violates one?

[Reviewed by Robohands]

@freddymeta
freddymeta force-pushed the feat/daterange-max-span branch from eb0024a to ef470b9 Compare August 18, 2026 01:25
@github-actions
github-actions Bot requested a review from cixzhang August 18, 2026 01:25
@github-actions github-actions Bot added the needs:design-review Affects visuals — Design should review label Aug 18, 2026
@freddymeta

Copy link
Copy Markdown
Contributor Author

Thanks — all three addressed:

minRangeSpan enforcement. The forbidden band is now correct: with the anchor placed, end-days closer than the minimum are disabled (distance > 0 && distance < minRangeSpan - 1, both endpoints counted). The one case that slipped through was the anchor itself — clicking the same day twice — which is now handled below.

Anchor toggle-to-clear. Clicking the in-progress start again clears it instead of committing a zero-length range, so you can move the start even when minRangeSpan has disabled the days around it. minRangeSpan intentionally leaves the anchor enabled precisely so this toggle stays reachable. It announces via a new rangeClearedAnnounce live-region string.

Preset vs cap. A preset whose range violates maxRangeSpan/minRangeSpan is now disabled (visible but not committable), rather than allowed to override the cap — mirroring how the calendar disables out-of-window days. Documented on the maxRangeSpan prop.

Tests added for the anchor-clear and the disabled-preset paths; full suite green (Calendar + DateRangeInput, 125 tests), build/typecheck/lint/i18n-catalog clean.

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, all three land. Walked it in Chrome: the forbidden band is right, the anchor clears, the 30-day preset is disabled.

[Reviewed by Robohands]

@cixzhang
cixzhang dismissed their stale review August 19, 2026 04:54

All three asks addressed; walked the flow in Chromium.

@github-actions github-actions Bot removed the needs:code-review High-risk change (new package/component/API) — needs human code review before merge label Aug 19, 2026
@cixzhang
cixzhang merged commit 1cd52d9 into main Aug 19, 2026
21 checks passed
@github-actions
github-actions Bot deleted the feat/daterange-max-span branch August 19, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. community Authored by a community contributor (not on the eng/design team) needs:design-review Affects visuals — Design should review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants