From b263c17677c99933f3308a70ab27aebc4a89986c Mon Sep 17 00:00:00 2001 From: Andrey Belokopytov Date: Tue, 28 Jan 2025 18:23:37 +0300 Subject: [PATCH 1/5] feat: add dd/mm and mm/dd date modes --- .../src/tests/kit/date/date-mode.cy.ts | 86 +++++++++++++++++++ .../pages/kit/date/date-mask-doc.component.ts | 2 + .../processors/min-max-date-postprocessor.ts | 16 ++-- projects/kit/src/lib/types/date-mode.ts | 2 + .../src/lib/utils/date/is-calendar-date.ts | 3 + 5 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 projects/kit/src/lib/utils/date/is-calendar-date.ts diff --git a/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts b/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts index 25f5e473e..905280039 100644 --- a/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts +++ b/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts @@ -203,5 +203,91 @@ describe('Date', () => { .should('have.prop', 'selectionEnd', '2025'.length); }); }); + + describe('dd/mm', () => { + beforeEach(() => { + cy.visit(`/${DemoPath.Date}/API?mode=dd%2Fmm`); + cy.get('#demo-content input') + .should('be.visible') + .first() + .focus() + .as('input'); + }); + + it('"dd/mm" => 14.07', () => { + cy.get('@input') + .type('1407') + .should('have.value', '14.07') + .should('have.prop', 'selectionStart', '14.07'.length) + .should('have.prop', 'selectionEnd', '14.07'.length); + }); + + it('"dd/mm" => 01.01', () => { + cy.get('@input') + .type('0101') + .should('have.value', '01.01') + .should('have.prop', 'selectionStart', '01.11'.length) + .should('have.prop', 'selectionEnd', '01.11'.length); + }); + + it('"dd/mm" => 05.11', () => { + cy.get('@input') + .type('511') + .should('have.value', '05.11') + .should('have.prop', 'selectionStart', '05.11'.length) + .should('have.prop', 'selectionEnd', '05.11'.length); + }); + + it('"dd/mm" => 05.05', () => { + cy.get('@input') + .type('55') + .should('have.value', '05.05') + .should('have.prop', 'selectionStart', '05.05'.length) + .should('have.prop', 'selectionEnd', '05.05'.length); + }); + }); + + describe('mm/dd', () => { + beforeEach(() => { + cy.visit(`/${DemoPath.Date}/API?mode=mm%2Fdd`); + cy.get('#demo-content input') + .should('be.visible') + .first() + .focus() + .as('input'); + }); + + it('"mm/dd" => 02.29', () => { + cy.get('@input') + .type('0229') + .should('have.value', '02.29') + .should('have.prop', 'selectionStart', '02.29'.length) + .should('have.prop', 'selectionEnd', '02.29'.length); + }); + + it('"mm/dd" => 01.01', () => { + cy.get('@input') + .type('0101') + .should('have.value', '01.01') + .should('have.prop', 'selectionStart', '01.01'.length) + .should('have.prop', 'selectionEnd', '01.01'.length); + }); + + it('"mm/dd" => 09.12', () => { + cy.get('@input') + .type('912') + .should('have.value', '09.12') + .should('have.prop', 'selectionStart', '09.12'.length) + .should('have.prop', 'selectionEnd', '09.12'.length); + }); + + it('"mm/dd" => 09.09', () => { + cy.get('@input') + .type('99') + .should('have.value', '09.09') + .should('have.prop', 'selectionStart', '09.09'.length) + .should('have.prop', 'selectionEnd', '09.09'.length); + }); + }); }); }); diff --git a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts index 9b1510c7c..d7cd56cf0 100644 --- a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts +++ b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts @@ -46,7 +46,9 @@ export default class DateMaskDocComponent implements GeneratorOptions { }; protected readonly modeOptions = [ + 'dd/mm', 'dd/mm/yyyy', + 'mm/dd', 'mm/dd/yyyy', 'yyyy/mm/dd', 'mm/yy', diff --git a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts index 55bb7fece..8d6299ac2 100644 --- a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts +++ b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts @@ -10,6 +10,7 @@ import { segmentsToDate, toDateString, } from '../utils'; +import {isCalendarDate} from '../utils/date/is-calendar-date'; import {raiseSegmentValueToMin} from '../utils/date/raise-segment-value-to-min'; export function createMinMaxDatePostprocessor({ @@ -48,12 +49,17 @@ export function createMinMaxDatePostprocessor({ continue; } - const date = segmentsToDate(parsedDate); - const clampedDate = clamp(date, min, max); + if (isCalendarDate(dateModeTemplate, dateSegmentSeparator)) { + const date = segmentsToDate(parsedDate); - validatedValue += toDateString(dateToSegments(clampedDate), { - dateMode: dateModeTemplate, - }); + const clampedDate = clamp(date, min, max); + + validatedValue += toDateString(dateToSegments(clampedDate), { + dateMode: dateModeTemplate, + }); + } else { + validatedValue += dateString; + } } return { diff --git a/projects/kit/src/lib/types/date-mode.ts b/projects/kit/src/lib/types/date-mode.ts index ce6e7662d..5611cc732 100644 --- a/projects/kit/src/lib/types/date-mode.ts +++ b/projects/kit/src/lib/types/date-mode.ts @@ -1,5 +1,7 @@ export type MaskitoDateMode = + | 'dd/mm' | 'dd/mm/yyyy' + | 'mm/dd' | 'mm/dd/yyyy' | 'mm/yy' | 'mm/yyyy' diff --git a/projects/kit/src/lib/utils/date/is-calendar-date.ts b/projects/kit/src/lib/utils/date/is-calendar-date.ts new file mode 100644 index 000000000..40eb54bae --- /dev/null +++ b/projects/kit/src/lib/utils/date/is-calendar-date.ts @@ -0,0 +1,3 @@ +export function isCalendarDate(template: string, separator: string): boolean { + return template !== `dd${separator}mm` && template !== `mm${separator}dd`; +} From cf993ae20612b1e176bee49e71a474b0f97e8dc8 Mon Sep 17 00:00:00 2001 From: Andrey Belokopytov Date: Wed, 29 Jan 2025 10:56:04 +0300 Subject: [PATCH 2/5] fix: change the order of the mode options --- projects/demo/src/pages/kit/date/date-mask-doc.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts index d7cd56cf0..a13eb30c3 100644 --- a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts +++ b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts @@ -46,11 +46,11 @@ export default class DateMaskDocComponent implements GeneratorOptions { }; protected readonly modeOptions = [ - 'dd/mm', 'dd/mm/yyyy', 'mm/dd', 'mm/dd/yyyy', 'yyyy/mm/dd', + 'dd/mm', 'mm/yy', 'mm/yyyy', 'yyyy/mm', From e7577bc44a2eca4dd84599491ce6b4f77658429e Mon Sep 17 00:00:00 2001 From: Andrey Belokopytov Date: Wed, 29 Jan 2025 11:08:21 +0300 Subject: [PATCH 3/5] fix: change the order of the mode options --- projects/demo/src/pages/kit/date/date-mask-doc.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts index a13eb30c3..4ffaba503 100644 --- a/projects/demo/src/pages/kit/date/date-mask-doc.component.ts +++ b/projects/demo/src/pages/kit/date/date-mask-doc.component.ts @@ -47,10 +47,10 @@ export default class DateMaskDocComponent implements GeneratorOptions { protected readonly modeOptions = [ 'dd/mm/yyyy', - 'mm/dd', 'mm/dd/yyyy', 'yyyy/mm/dd', 'dd/mm', + 'mm/dd', 'mm/yy', 'mm/yyyy', 'yyyy/mm', From 076c72887266527e3be2a73d037c4aeb48bc1f27 Mon Sep 17 00:00:00 2001 From: Andrey Belokopytov Date: Thu, 30 Jan 2025 18:53:02 +0300 Subject: [PATCH 4/5] feat: set default year for the date --- .../src/tests/kit/date/date-mode.cy.ts | 16 ++++++++++++++ .../processors/min-max-date-postprocessor.ts | 21 ++++++++++--------- .../src/lib/utils/date/is-calendar-date.ts | 3 --- 3 files changed, 27 insertions(+), 13 deletions(-) delete mode 100644 projects/kit/src/lib/utils/date/is-calendar-date.ts diff --git a/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts b/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts index 905280039..40ba54802 100644 --- a/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts +++ b/projects/demo-integrations/src/tests/kit/date/date-mode.cy.ts @@ -245,6 +245,14 @@ describe('Date', () => { .should('have.prop', 'selectionStart', '05.05'.length) .should('have.prop', 'selectionEnd', '05.05'.length); }); + + it('dd/mm" => 01.05', () => { + cy.get('@input') + .type('3104') + .should('have.value', '01.05') + .should('have.prop', 'selectionStart', '01.05'.length) + .should('have.prop', 'selectionEnd', '01.05'.length); + }); }); describe('mm/dd', () => { @@ -288,6 +296,14 @@ describe('Date', () => { .should('have.prop', 'selectionStart', '09.09'.length) .should('have.prop', 'selectionEnd', '09.09'.length); }); + + it('dd/mm" => 05.01', () => { + cy.get('@input') + .type('431') + .should('have.value', '05.01') + .should('have.prop', 'selectionStart', '05.01'.length) + .should('have.prop', 'selectionEnd', '05.01'.length); + }); }); }); }); diff --git a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts index 8d6299ac2..884747c90 100644 --- a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts +++ b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts @@ -10,9 +10,10 @@ import { segmentsToDate, toDateString, } from '../utils'; -import {isCalendarDate} from '../utils/date/is-calendar-date'; import {raiseSegmentValueToMin} from '../utils/date/raise-segment-value-to-min'; +const LEAP_YEAR = '1972'; + export function createMinMaxDatePostprocessor({ dateModeTemplate, min = DEFAULT_MIN_DATE, @@ -49,17 +50,17 @@ export function createMinMaxDatePostprocessor({ continue; } - if (isCalendarDate(dateModeTemplate, dateSegmentSeparator)) { - const date = segmentsToDate(parsedDate); + if (!parsedDate.year) { + parsedDate.year = LEAP_YEAR; + } + + const date = segmentsToDate(parsedDate); - const clampedDate = clamp(date, min, max); + const clampedDate = clamp(date, min, max); - validatedValue += toDateString(dateToSegments(clampedDate), { - dateMode: dateModeTemplate, - }); - } else { - validatedValue += dateString; - } + validatedValue += toDateString(dateToSegments(clampedDate), { + dateMode: dateModeTemplate, + }); } return { diff --git a/projects/kit/src/lib/utils/date/is-calendar-date.ts b/projects/kit/src/lib/utils/date/is-calendar-date.ts deleted file mode 100644 index 40eb54bae..000000000 --- a/projects/kit/src/lib/utils/date/is-calendar-date.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function isCalendarDate(template: string, separator: string): boolean { - return template !== `dd${separator}mm` && template !== `mm${separator}dd`; -} From e25440f27fa66816e12086a3e37d6641c4f2116d Mon Sep 17 00:00:00 2001 From: Andrei Belokopytov Date: Mon, 3 Feb 2025 11:52:08 +0300 Subject: [PATCH 5/5] refactor: suggestion Co-authored-by: Nikita Barsukov --- .../kit/src/lib/processors/min-max-date-postprocessor.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts index 884747c90..9eb541e13 100644 --- a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts +++ b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts @@ -50,11 +50,7 @@ export function createMinMaxDatePostprocessor({ continue; } - if (!parsedDate.year) { - parsedDate.year = LEAP_YEAR; - } - - const date = segmentsToDate(parsedDate); + const date = segmentsToDate({year: LEAP_YEAR, ...parsedDate}); const clampedDate = clamp(date, min, max);