From 4fd97c0a7f867ac9f3b14ea11d6edfc348e0ed4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Fonseca?= Date: Tue, 28 Apr 2026 16:41:21 +0100 Subject: [PATCH 1/3] fix: improve min and max handling and date parsing --- .../src/components/datepicker/datepicker.ts | 20 ++++++++++-- packages/components/src/utilities/date.ts | 31 +++++++------------ 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/packages/components/src/components/datepicker/datepicker.ts b/packages/components/src/components/datepicker/datepicker.ts index b4da4e6265..0f94894bc9 100644 --- a/packages/components/src/components/datepicker/datepicker.ts +++ b/packages/components/src/components/datepicker/datepicker.ts @@ -560,8 +560,24 @@ export default class SdDatepicker extends SolidElement implements SolidFormContr } private inMinMax(d: Date): boolean { - const min = this.min === null ? null : this.parseISO(String(this.min)); - const max = this.max === null ? null : this.parseISO(String(this.max)); + const normalizeBound = (value: string | number | Date | undefined | null): Date | null => { + if (value === undefined || value === null) return null; + if (value instanceof Date) { + return DateUtils.startOfDayLocal(value); + } + if (typeof value === 'number') { + return DateUtils.startOfDayLocal(new Date(value)); + } + if (typeof value === 'string') { + // Allow both attribute-style strings and programmatic assignment. + const parsed = this.parseISO(value); + return parsed ? DateUtils.startOfDayLocal(parsed) : null; + } + return null; + }; + + const min = normalizeBound(this.min as string | number | Date | undefined | null); + const max = normalizeBound(this.max as string | number | Date | undefined | null); if (min && d < min) return false; if (max && d > max) return false; diff --git a/packages/components/src/utilities/date.ts b/packages/components/src/utilities/date.ts index 66a7b11224..b2d7a0a124 100644 --- a/packages/components/src/utilities/date.ts +++ b/packages/components/src/utilities/date.ts @@ -26,26 +26,19 @@ export const DateUtils = { parseLocalISO: (iso: string | null): Date | null => { if (!iso) return null; - let y: number; - let m: number; - let d: number; + const trimmed = iso.trim(); + if (!trimmed) return null; - // support ISO - if (/^\d{4}-\d{2}-\d{2}$/.test(iso)) { - const parts = iso.split('-'); - y = Number(parts[0]); - m = Number(parts[1]) - 1; - d = Number(parts[2]); - } - // support date with dots "YYYY.MM.DD" - else if (/^\d{4}\.\d{2}\.\d{2}$/.test(iso)) { - const parts = iso.split('.'); - y = Number(parts[0]); - m = Number(parts[1]) - 1; - d = Number(parts[2]); - } else { - return null; - } + // Normalize dots and slashes to hyphens so we support + // YYYY-MM-DD, YYYY.MM.DD and YYYY/MM/DD uniformly. + const normalized = trimmed.replace(/[./]/g, '-'); + + const match = normalized.match(/^(\d{4})-(\d{2})-(\d{2})$/); + if (!match) return null; + + const y = Number(match[1]); + const m = Number(match[2]) - 1; + const d = Number(match[3]); const date = new Date(y, m, d); return Number.isNaN(date.getTime()) ? null : date; From 2c36c711f19d139c60c6283619d260aaaf8a40bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Fonseca?= Date: Tue, 28 Apr 2026 16:43:26 +0100 Subject: [PATCH 2/3] test: extend min and max test --- .../src/components/datepicker/datepicker.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/components/src/components/datepicker/datepicker.test.ts b/packages/components/src/components/datepicker/datepicker.test.ts index 8eed838104..4d43f68ec2 100644 --- a/packages/components/src/components/datepicker/datepicker.test.ts +++ b/packages/components/src/components/datepicker/datepicker.test.ts @@ -402,6 +402,22 @@ describe('', () => { expect(el.checkValidity()).to.be.false; expect(input.getAttribute('aria-invalid')).to.equal('true'); }); + + it('should respect min and max when set programmatically as Date objects', async () => { + const el = await fixture(html``); + + el.min = new Date(2025, 11, 9); // 2025-12-09 + el.max = new Date(2025, 11, 12); // 2025-12-12 + await el.updateComplete; + + el.show(); + await el.updateComplete; + + const dayButtons = Array.from(el.shadowRoot!.querySelectorAll('button.day')); + const enabledDays = dayButtons.filter(btn => !btn.classList.contains('disabled')); + + expect(enabledDays.length).to.equal(4); + }); }); describe('set initial month displayed with viewMonth attribute', () => { From 3cbb7f94c4f141ddb52a0e9a22b46ace72aaaf25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Se=CC=81rgio=20Fonseca?= Date: Tue, 28 Apr 2026 16:54:33 +0100 Subject: [PATCH 3/3] chore: add changeset --- .changeset/red-terms-hunt.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/red-terms-hunt.md diff --git a/.changeset/red-terms-hunt.md b/.changeset/red-terms-hunt.md new file mode 100644 index 0000000000..c48d923d7f --- /dev/null +++ b/.changeset/red-terms-hunt.md @@ -0,0 +1,5 @@ +--- +'@solid-design-system/components': patch +--- + +Improved handling of `min` and `max` attributes in `sd-datepicker` and enhanced internal `parseLocalISO` date utility to accept slash-separated dates (`YYYY/MM/DD`) in addition to hyphen and dot separators.