diff --git a/src/components/duet-date-picker/date-utils.ts b/src/components/duet-date-picker/date-utils.ts index 4ffd781..c7d3eab 100644 --- a/src/components/duet-date-picker/date-utils.ts +++ b/src/components/duet-date-picker/date-utils.ts @@ -10,6 +10,18 @@ export enum DaysOfWeek { Saturday = 6, } +export class DateInvalidException implements Error { + constructor(message, name, date) { + this.message = message + this.name = name + this.date = date + } + + message: string + name: string + date: Date +} + export function createDate(year: string, month: string, day: string): Date { var dayInt = parseInt(day, 10) var monthInt = parseInt(month, 10) @@ -26,10 +38,31 @@ export function createDate(year: string, month: string, day: string): Date { yearInt > 0 if (isValid) { - return new Date(yearInt, monthInt - 1, dayInt) + const date = new Date(yearInt, monthInt - 1, dayInt) + + if (isDateChanged(date, dayInt, monthInt, yearInt)) { + throw new DateInvalidException("Invalid date", "Invalid date", date) + } + + return date } } +/** + * + * @param date + * @param day + * @param month + * @param year + */ +function isDateChanged(date: Date, day: number, month: number, year: number): boolean { + if (date.getDate() != day || date.getMonth() + 1 != month || date.getFullYear() != year) { + return true + } + + return false +} + /** * @param value date string in ISO format YYYY-MM-DD */ @@ -41,7 +74,9 @@ export function parseISODate(value: string): Date { const matches = value.match(ISO_DATE_FORMAT) if (matches) { - return createDate(matches[1], matches[2], matches[3]) + try { + return createDate(matches[1], matches[2], matches[3]) + } catch (e) {} } } diff --git a/src/components/duet-date-picker/duet-date-picker.tsx b/src/components/duet-date-picker/duet-date-picker.tsx index ad1d811..4d4c640 100644 --- a/src/components/duet-date-picker/duet-date-picker.tsx +++ b/src/components/duet-date-picker/duet-date-picker.tsx @@ -88,6 +88,12 @@ export type DuetDatePickerOpenEvent = { export type DuetDatePickerCloseEvent = { component: "duet-date-picker" } +export type DuetDatePickerDateNotValidEvent = { + component: "duet-date-picker" + valueAsDate: Date + value: string + enteredValue: string +} export type DuetDatePickerDirection = "left" | "right" const DISALLOWED_CHARACTERS = /[^0-9\.\/\-]+/g @@ -253,6 +259,11 @@ export class DuetDatePicker implements ComponentInterface { */ @Event() duetClose: EventEmitter + /** + * Event emitted the date picker has an invalid date. + */ + @Event() duetNotValidDate: EventEmitter + connectedCallback() { this.createDateFormatters() } @@ -552,9 +563,18 @@ export class DuetDatePicker implements ComponentInterface { // clean up any invalid characters cleanValue(target, DISALLOWED_CHARACTERS) - const parsed = this.dateAdapter.parse(target.value, createDate) - if (parsed || target.value === "") { - this.setValue(parsed) + try { + const parsed = this.dateAdapter.parse(target.value, createDate) + if (parsed || target.value === "") { + this.setValue(parsed) + } + } catch (e) { + this.duetNotValidDate.emit({ + component: "duet-date-picker", + valueAsDate: e.date, + value: printISODate(e.date), + enteredValue: target.value, + }) } } diff --git a/src/components/duet-date-picker/readme.md b/src/components/duet-date-picker/readme.md index c5bd4db..f7e73cb 100644 --- a/src/components/duet-date-picker/readme.md +++ b/src/components/duet-date-picker/readme.md @@ -26,13 +26,14 @@ ## Events -| Event | Description | Type | -| ------------ | ----------------------------------------------- | ----------------------------------------------------------------------------------- | -| `duetBlur` | Event emitted the date picker input is blurred. | `CustomEvent<{ component: "duet-date-picker"; }>` | -| `duetChange` | Event emitted when a date is selected. | `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; }>` | -| `duetClose` | Event emitted the date picker modal is closed. | `CustomEvent<{ component: "duet-date-picker"; }>` | -| `duetFocus` | Event emitted the date picker input is focused. | `CustomEvent<{ component: "duet-date-picker"; }>` | -| `duetOpen` | Event emitted the date picker modal is opened. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| Event | Description | Type | +| ------------------ |----------------------------------------------------| --------------------------------------------------------------------------------------------------------- | +| `duetBlur` | Event emitted the date picker input is blurred. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| `duetChange` | Event emitted when a date is selected. | `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; }>` | +| `duetClose` | Event emitted the date picker modal is closed. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| `duetFocus` | Event emitted the date picker input is focused. | `CustomEvent<{ component: "duet-date-picker"; }>` | +| `duetNotValidDate` | Event emitted the date picker has an invalid date. | `CustomEvent<{ component: "duet-date-picker"; valueAsDate: Date; value: string; enteredValue: string; }>` | +| `duetOpen` | Event emitted the date picker modal is opened. | `CustomEvent<{ component: "duet-date-picker"; }>` | ## Methods