Skip to content

Fix(core date input) month list disable offset eix 314 - #2822

Open
benjgil wants to merge 4 commits into
mainfrom
fix(core-date-input)-month-list-disable-offset-EIX-314
Open

benjgil wants to merge 4 commits into
mainfrom
fix(core-date-input)-month-list-disable-offset-EIX-314

Conversation

@benjgil

@benjgil benjgil commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

💡 What is the current behavior?

There are numerous bugs in the code related to mismatched indexes being compared across the logic. E.g. the month disabling code that compares 0-base index month names to 1-base month list.

GitHub Issue Number: #2780

🆕 What is the new behavior?

This PR fixes any existing Date index mismatches and removes the scope for any further mismatches via normalising all DateTime logic to use consistent Luxon objects and then resolve strings and values directly from these objects when required, rather than using the strings and values for comparison.

Tests have been added to ensure behaviour is kept consistent, and to cover the revealed prior bugs.

🏁 Checklist

A pull request can only be merged if all of these conditions are met (where applicable):

  • 🦮 Accessibility (a11y) features were implemented
  • 🗺️ Internationalization (i18n) - no hard coded strings
  • 📲 Responsiveness - components handle viewport changes and content overflow gracefully
  • 📕 Add or update a Storybook story
  • 📄 Documentation was reviewed/updated siemens/ix-docs
  • 🧪 Unit tests were added/updated and pass (pnpm test)
  • 📸 Visual regression tests were added/updated and pass (Guide)
  • 🧐 Static code analysis passes (pnpm lint)
  • 🏗️ Successful compilation (pnpm build, changes pushed)

👨‍💻 Help & support

Summary by CodeRabbit

  • New Features

    • Improved date-picker month and year navigation using more reliable calendar handling.
    • Added localized month and weekday labels with support for configurable week starts.
    • Improved enforcement of minimum and maximum date ranges for day, month, and year selection.
    • Added support for Sunday-first calendar layouts.
  • Bug Fixes

    • Prevented invalid calendar selections and corrected date positioning across locales and week-start configurations.
  • Tests

    • Added comprehensive coverage for calendar calculations, date ranges, localization, leap years, and week layouts.

benjgil and others added 4 commits September 6, 2026 23:36
Luxon has two numbering systems that are each internally correct: ISO
ordinals (`DateTime.month` 1-12, `DateTime.weekday` 1-7 Monday=1) and
plain array offsets (`Info.months()` / `Info.weekdays()` are 0-based).
Bugs appear wherever one is compared against or used to index the other.
`calendar-units.ts` had drawn the boundary in index-space, which is the
losing side: DateTime touchpoints far outnumber array touchpoints, so
every helper was another chance to convert in the wrong direction.

Invert it. A calendar position is now carried as a `DateTime` and never
as a bare unit number, and names are derived by formatting that DateTime
rather than by indexing a name array. An array index no longer escapes a
single `.map()`, so neither base is written down outside the util.

- `calendar-units.ts` becomes a thin calendar vocabulary over DateTime
  (`monthsOfYear`, `monthNameOf`, `dayOfMonth`, `weekdayNamesFrom`,
  `weekdayColumnOf`, the `is*WithinRange` predicates). Every
  index-conversion helper is gone.
- `date-picker.tsx` carries `selectedMonthDate` / `tempMonthDate` as
  DateTime rather than as four separate year/month numbers.
- The `isWithinMinMaxMonth` off-by-one is fixed structurally, not
  patched: because a month now carries its own year, the
  ordinal-vs-offset mismatch is not expressible.
- Drop the dead `_minDateObj` / `_maxDateObj` fields. They were assigned
  via the locale-aware `parseWithLocale` but never read, while the live
  path re-parsed through the locale-blind `DateTime.fromFormat` on every
  `getDayClasses` call (~84 parses per render). This is a deliberate
  behaviour change: min/max bounds now honour the locale.
- Retarget the `calendarUnitRules` ESLint block. It named helpers that
  no longer exist, and `no-restricted-syntax` is type-blind so it cannot
  enforce transport anyway - the signatures do that. Lint now guards the
  step before: the ways a bare unit number gets manufactured, including
  a new ban on `Info.months()` / `Info.weekdays()`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@benjgil
benjgil requested a review from a team as a code owner September 17, 2026 14:35
@benjgil
benjgil requested a review from alexkaduk September 17, 2026 14:35
@changeset-bot

changeset-bot Bot commented Sep 17, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6a59f13

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@netlify

netlify Bot commented Sep 17, 2026

Copy link
Copy Markdown

Deploy Preview for ix-storybook ready!

Name Link
🔨 Latest commit 6a59f13
🔍 Latest deploy log https://app.netlify.com/projects/ix-storybook/deploys/6aabfac820bad10009df2641
😎 Deploy Preview https://deploy-preview-2822--ix-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 672ec5f9-0bd3-443f-9a81-ad5d63cfcb3b

📥 Commits

Reviewing files that changed from the base of the PR and between 4668b1a and 6a59f13.

📒 Files selected for processing (5)
  • packages/core/eslint.config.cjs
  • packages/core/src/components/date-picker/date-picker.tsx
  • packages/core/src/components/date-picker/test/date-picker.ct.ts
  • packages/core/src/components/utils/calendar-units.ts
  • packages/core/src/components/utils/test/calendar-units.spec.ts

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.


📝 Walkthrough

Walkthrough

Changes

Calendar unit migration

Layer / File(s) Summary
Calendar helper contracts and tests
packages/core/src/components/utils/calendar-units.ts, packages/core/src/components/utils/test/calendar-units.spec.ts
Adds DateTime-based helpers for month, day, weekday, week-start, and range calculations with comprehensive tests.
Date picker DateTime migration
packages/core/src/components/date-picker/date-picker.tsx, packages/core/src/components/date-picker/test/date-picker.ct.ts
Replaces separate numeric month/year state with DateTime state and updates navigation, rendering, range checks, weekday handling, and component tests.
Calendar usage lint rules
packages/core/eslint.config.cjs
Adds shared assertion rules and date-component restrictions for direct calendar-unit access and multi-argument Date construction.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~30 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 6a59f

The calendar migration preserves the inspected date-range behavior, with no concrete merge-blocking risk identified.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title identifies the core change: fixing the month-list disable offset in the date input. It is related to the main objective, although it contains a typo and uses awkward phrasing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 10 functions across 5 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@sonarqubecloud

Copy link
Copy Markdown

@alexkaduk

Copy link
Copy Markdown
Collaborator

This is a user-facing month min/max bug fix, so it needs a changeset for @siemens/ix (patch) or it will not ship in release notes.

@@ -428,12 +454,10 @@ export class DatePicker
*/
@Method()
async updateSelectedYearMonth(date: DateTime) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

renderMonths() builds the list from tempMonthDate.year, but updateSelectedYearMonth only assigns selectedMonthDate.

from/to watchers and ix-date-dropdown (re-select same range) call this method, so the calendar can show year A while the month dropdown still lists/disables year B.

Please also set this.tempMonthDate = this.selectedMonthDate here, same as selectMonth / changeCalendarView.

'enables the month a single-month range sits in',
async ({ mount, page }) => {
await mount(
`<ix-date-picker from="2026/07/06" min-date="2026/07/05" max-date="2026/07/15" single-selection></ix-date-picker>`

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

These asserts use English month names (July, June, …) but the mounts do not set locale="en". The translation test in this file already pins locale="de", so this will fail on a non-English runner.

Please add locale="en" to these mounts. A case matching #2780 (min-date="2026/03/31" / max-date="2027/01/31") would also help.

@alexkaduk

Copy link
Copy Markdown
Collaborator

The PR title (Fix(core date input) month list disable offset eix 314) does not match <type>[optional <scope>]: <description> from .github/instructions/code-review.instructions.md (same rule in AGENTS.md).

Please rename the pull request to something like fix(core/date-picker): correct month dropdown min/max disable offset EIX-314.

Also please rebase onto latest main. #2767 extracted DatePickerYearMonth after this branch’s last merge; this PR types updateSelectedYearMonth as DateTime again, which is the right call now that month is no longer a bare number — just avoid leaving the unused type behind.

@@ -428,12 +454,10 @@ export class DatePicker
*/
@Method()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The DateTime model is good! however the displayed month is still two clocks (selectedMonthDate vs tempMonthDate) written four different ways.

renderMonths() uses tempMonthDate.year, while the header and grid use selectedMonthDate. updateSelectedYearMonth (from/to watchers and ix-date-dropdown) only sets selectedMonthDate, so the calendar can show year A while the month list still disables year B. The JSDoc says tempMonthDate diverges only while picking a year before a month, but year click already commits both.

Pls consider to route all four paths through one setter, e.g. setDisplayedMonth(month), that assigns both to month.startOf('month'). Keep the current UX (year click updates the calendar immediately). Then the tempMonthDate comment should match that, or go away.

@alexkaduk alexkaduk Sep 18, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It is related to the next comment. Pls consider both as one suggestion/finding


import { DateTime, Info } from 'luxon';

/**

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A lot of the new commentary restates the 0- vs 1-based rule (file essay, almost every helper, ESLint block, and tempMonthDate / weekStart in date-picker.tsx). That is heavier than nearby core utils (date-time-locale.ts is a short JSDoc only when the contract is not obvious).

Please keep public @Prop/@Method docs, one short module note, and the ESLint message strings. Trim the rest — including the tempMonthDate JSDoc if we keep a single setDisplayedMonth (it currently describes a year-then-month flow that year click does not do). Also the locale prop still says locale sets weekday order; weekStartIndex does.

@alexkaduk

Copy link
Copy Markdown
Collaborator

ix-date-input exposes weekStartIndex but does not pass it to the nested ix-date-picker (date-input.tsx, the <ix-date-picker> around line 608). ix-date-dropdown and ix-datetime-picker already forward it, so on date-input the public prop is a no-op (week always starts Monday).

Please consider to add weekStartIndex={this.weekStartIndex} on that nested picker.

allConfig: js.configs.all,
});

// `no-restricted-syntax` is not additive across flat-config objects - a later

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reading eslint.config.cjs: this PR extracts the existing ! / definite-assignment no-restricted-syntax rules so they can be re-spread, then adds calendarUnitRules on the date-* components (ban .month, .weekday, Info.months() / Info.weekdays(), new Date(y, m, …); tests and calendar-units.ts excluded).

That is a guardrail so we do not mix Luxon 1-based ordinals with 0-based name arrays again. What I see it is not required for the month min/max fix — calendar-units + the picker DateTime state already do that. Flat config replaces no-restricted-syntax rather than merging, which is why the ! rules had to be extracted.

CI should not fail if this file is reverted on this PR: core lint is still the main ! rules, and the new picker code does not trip them.

Please move the ESLint change to a follow-up/new PR, so this PR stays the #2780 / EIX-314 behaviour fix.

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.

2 participants