Skip to content

fix(components): [date-picker-panel]honor disabledDate on adjusted range#24085

Merged
Dsaquel merged 3 commits into
element-plus:devfrom
LostElkByte:fix/time-picker-disabled-date-range
May 13, 2026
Merged

fix(components): [date-picker-panel]honor disabledDate on adjusted range#24085
Dsaquel merged 3 commits into
element-plus:devfrom
LostElkByte:fix/time-picker-disabled-date-range

Conversation

@LostElkByte
Copy link
Copy Markdown
Contributor

@LostElkByte LostElkByte commented Apr 17, 2026

fix #24075

Fixes a bug where the auto-adjusted date in datetimerange picker could land on a disabled date.

Reproduction:

  1. Set disabledDate to disable dates after 2026-04-17
  2. Initial value: 2026-02-20 ~ 2026-03-19
  3. Type 2026-03-20 in the start date input
  4. End date auto-adjusts to 2026-04-20 (disabled) ❌

After fix: End date adjusts to 2026-04-17 (nearest valid date) ✅

Summary by CodeRabbit

  • Bug Fixes

    • Date range picker now avoids selecting disabled dates for the opposite endpoint by moving to the nearest valid date; if no valid range exists, both endpoints converge to a single valid date.
  • Tests

    • Added tests that verify auto-adjustment behavior when disabled dates are present, including cases where endpoints converge and where adjustments respect non-disabled boundaries.

Review Change Stack

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 266c7d3c-a015-4217-8b7e-355e58e504bf

📥 Commits

Reviewing files that changed from the base of the PR and between 240fa8a and 705af8b.

📒 Files selected for processing (2)
  • packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx
  • packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/components/date-picker-panel/tests/date-picker-panel.test.tsx

📝 Walkthrough

Walkthrough

Panel-date-range adds a helper that finds the nearest non-disabled date by stepping day-by-day toward a target, and uses it in linked-panel auto-adjust logic; tests were added to validate start/end auto-adjustment and convergence when intervening dates are all disabled.

Changes

DatePickerPanel datetimerange

Layer / File(s) Summary
Finder helper
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
Adds findValidDateToward(from, toward) which walks day-by-day toward a target and returns the first non-disabled date (falls back to from).
handleDateInput: min-side
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
When type === 'min' and !maxDate.value (linked panels), replace direct minDate + 1 month assignment with findValidDateToward(minDate + 1 month, minDate) for rightDate/maxDate.
handleDateInput: max-side
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
When type === 'max' and !minDate.value (linked panels), replace direct maxDate - 1 month assignment with findValidDateToward(maxDate - 1 month, maxDate) for leftDate/minDate.
handleDateChange: min-side convergence
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
When a new minDate would exceed maxDate, adjust rightDate/maxDate using findValidDateToward(minDate + 1 month, minDate).
handleDateChange: max-side convergence
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
When a new maxDate would precede minDate, adjust leftDate/minDate using findValidDateToward(maxDate - 1 month, maxDate).
Tests — datetimerange behaviors
packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx
Adds three tests: end auto-adjusts when start changed, start auto-adjusts when end changed, and convergence when all intermediate dates are disabled (asserts resulting date is enabled).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • element-plus/element-plus#24011: Modifies date-range panel sync logic for opposite-bound auto-adjustment; related to how linked panels handle month-shifted adjustments.

Suggested reviewers

  • rzzf
  • Dsaquel
  • keeplearning66

Poem

🐰 I hopped through months and scanned each day,
I stepped toward dawn when paths were gray.
If a date is barred, I won't leap far—
I find the nearest light, where safe dates are.
A tiny hop, and the range is whole. ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: fixing date picker to honor disabledDate constraints when auto-adjusting range values.
Description check ✅ Passed The PR description includes a clear reproduction case, expected behavior after the fix, and reference to issue #24075, meeting the template requirements.
Linked Issues check ✅ Passed The code changes implement the core requirement from issue #24075: preventing auto-adjusted dates from falling on disabled dates by adding validation and fallback logic in handleDateInput and handleDateChange.
Out of Scope Changes check ✅ Passed All changes in both files (test additions and internal helper logic) are scoped to fixing the disabledDate constraint issue described in the linked issue, with no unrelated modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 17, 2026

Open in StackBlitz

pnpm add https://pkg.pr.new/element-plus@24085
npm i https://pkg.pr.new/element-plus@24085
yarn add https://pkg.pr.new/[email protected]

commit: 705af8b

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx (1)

1189-1225: Convergence case is well-tested.

This is the important boundary test — it locks in the behavior that a fully-disabled span between minDate and minDate+1month collapses both endpoints to minDate rather than leaving maxDate on a disabled day. Consider adding a symmetric convergence test for the 'max' branch (entering an end date when every prior month day is disabled) to guard against future regressions in the type === 'max' path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx`
around lines 1189 - 1225, Add a symmetric test that verifies the 'max'
convergence path: create a test like the existing one but set disabledDate (the
same function) to disable dates on/after 2026-03-21, mount DatePickerPanel with
v-model bound to the same value ref, locate the right-side input via pickerss
(the same query used earlier) using
'.el-date-range-picker__time-picker-wrap:nth-child(2) input' and simulate
changing the end date to '2026-03-20' (dispatch input and change events and
await nextTick()), then assert that value[0] and value[1] both format to
'2026-03-20' and that disabledDate(value[0])/disabledDate(value[1]) return
false; this mirrors the existing 'min' convergence test but exercises the type
=== "max" branch.
packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue (1)

783-795: Logic is correct — convergence to minDate is handled.

I traced the edge case where every day in (minDate, minDate+1month] is disabled: when cursor reaches minDate + 1 day, the isAfter(minDate.value) check passes, the loop body subtracts one day (cursor becomes minDate, which is guaranteed non-disabled by the early-return at Line 770), then assigns adjustedMax = minDate and breaks. So adjustedMax is never left at the original disabled minDate+1month value. Nice handling.

One optional suggestion: this block is nearly identical to the max branch at Lines 807–819 except for direction. Consider extracting a helper to reduce duplication:

♻️ Optional helper extraction
const findNonDisabledBoundary = (
  start: Dayjs,
  boundary: Dayjs,
  direction: 'backward' | 'forward'
): Dayjs => {
  if (!disabledDate || !disabledDate(start.toDate())) return start
  let cursor = start
  const step = direction === 'backward' ? -1 : 1
  const predicate =
    direction === 'backward'
      ? () => cursor.isAfter(boundary)
      : () => cursor.isBefore(boundary)
  while (predicate()) {
    cursor = cursor.add(step, 'day')
    if (!disabledDate(cursor.toDate())) return cursor
  }
  return cursor
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue`
around lines 783 - 795, The duplicated logic that searches for the nearest
non-disabled date around minDate/maxDate should be extracted into a reusable
helper (e.g., findNonDisabledBoundary) to remove the near-identical blocks
around adjustedMax/minDate.value and the later max-branch; implement a function
that accepts start Dayjs, boundary Dayjs, and direction ('backward'|'forward'),
encapsulates the disabledDate checks and the while-loop cursor movement, and
then replace the current loops that set
adjustedMax/rightDate.value/maxDate.value and the corresponding max-side code to
call this helper and assign its result.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx`:
- Around line 1189-1225: Add a symmetric test that verifies the 'max'
convergence path: create a test like the existing one but set disabledDate (the
same function) to disable dates on/after 2026-03-21, mount DatePickerPanel with
v-model bound to the same value ref, locate the right-side input via pickerss
(the same query used earlier) using
'.el-date-range-picker__time-picker-wrap:nth-child(2) input' and simulate
changing the end date to '2026-03-20' (dispatch input and change events and
await nextTick()), then assert that value[0] and value[1] both format to
'2026-03-20' and that disabledDate(value[0])/disabledDate(value[1]) return
false; this mirrors the existing 'min' convergence test but exercises the type
=== "max" branch.

In
`@packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue`:
- Around line 783-795: The duplicated logic that searches for the nearest
non-disabled date around minDate/maxDate should be extracted into a reusable
helper (e.g., findNonDisabledBoundary) to remove the near-identical blocks
around adjustedMax/minDate.value and the later max-branch; implement a function
that accepts start Dayjs, boundary Dayjs, and direction ('backward'|'forward'),
encapsulates the disabledDate checks and the while-loop cursor movement, and
then replace the current loops that set
adjustedMax/rightDate.value/maxDate.value and the corresponding max-side code to
call this helper and assign its result.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58ea04eb-32d5-4a0b-bab5-5995896ff136

📥 Commits

Reviewing files that changed from the base of the PR and between 79d4693 and c33e5ef.

📒 Files selected for processing (2)
  • packages/components/date-picker-panel/__tests__/date-picker-panel.test.tsx
  • packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

🧪 Playground Preview: https://element-plus.run/?pr=24085
Please comment the example via this playground if needed.

Copy link
Copy Markdown
Member

@keeplearning66 keeplearning66 left a comment

Choose a reason for hiding this comment

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

Would it be more complete to make the changes based on #24011? 🤔
We can wait for #24011 to be merged first.

@LostElkByte
Copy link
Copy Markdown
Contributor Author

Would it be more complete to make the changes based on #24011? 🤔 We can wait for #24011 to be merged first.

That works too. Their changes don’t really conflict functionally, but handling them one at a time would definitely be the safer approach.

…ed-date-range

# Conflicts:
#	packages/components/date-picker-panel/src/date-picker-com/panel-date-range.vue
@LostElkByte
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Copy Markdown
Member

@Dsaquel Dsaquel left a comment

Choose a reason for hiding this comment

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

Thanks!

@Dsaquel Dsaquel merged commit 24a447b into element-plus:dev May 13, 2026
17 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

@LostElkByte Thanks for your contribution! ❤️

@element-bot element-bot mentioned this pull request May 29, 2026
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Component] [time-picker] [BUG][el-date-picker] Manual month adjustment in datetimerange can produce dates outside disabledDate range

3 participants