From ec8628467814cff7dfae22668370236f402d8146 Mon Sep 17 00:00:00 2001 From: Stanislav Zaycev <102649815+KrollikRoddzer@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:06:47 +0300 Subject: [PATCH] feat(kit): `DateTime` supports configurable parameter `dateTimeSeparator` (#1143) --- .../date-time-date-time-separator.cy.ts | 61 +++++++++++++++++++ .../date-time/date-time-mask-doc.component.ts | 26 +++++--- .../date-time-mask-doc.template.html | 38 ++++++++++-- .../2-date-time-separator/component.ts | 39 ++++++++++++ .../examples/2-date-time-separator/mask.ts | 7 +++ .../{2-min-max => 3-min-max}/component.ts | 4 +- .../examples/{2-min-max => 3-min-max}/mask.ts | 0 .../min-max-range-length-postprocessor.ts | 4 +- .../src/lib/masks/date-time/date-time-mask.ts | 23 ++++--- .../min-max-date-time-postprocessor.ts | 26 +++++--- .../valid-date-time-preprocessor.ts | 15 ++--- .../tests/date-time-separator.spec.ts | 49 +++++++++++++++ .../utils/is-date-time-string-complete.ts | 16 +++-- .../date-time/utils/parse-date-time-string.ts | 16 +++-- ...ate-segments-zero-padding-postprocessor.ts | 2 +- .../processors/min-max-date-postprocessor.ts | 6 +- .../processors/normalize-date-preprocessor.ts | 10 +-- .../kit/src/lib/utils/date/to-date-string.ts | 29 +++++++-- .../lib/utils/date/validate-date-string.ts | 8 ++- 19 files changed, 315 insertions(+), 64 deletions(-) create mode 100644 projects/demo-integrations/src/tests/kit/date-time/date-time-date-time-separator.cy.ts create mode 100644 projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/component.ts create mode 100644 projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/mask.ts rename projects/demo/src/pages/kit/date-time/examples/{2-min-max => 3-min-max}/component.ts (92%) rename projects/demo/src/pages/kit/date-time/examples/{2-min-max => 3-min-max}/mask.ts (100%) create mode 100644 projects/kit/src/lib/masks/date-time/tests/date-time-separator.spec.ts diff --git a/projects/demo-integrations/src/tests/kit/date-time/date-time-date-time-separator.cy.ts b/projects/demo-integrations/src/tests/kit/date-time/date-time-date-time-separator.cy.ts new file mode 100644 index 000000000..5c650f68e --- /dev/null +++ b/projects/demo-integrations/src/tests/kit/date-time/date-time-date-time-separator.cy.ts @@ -0,0 +1,61 @@ +import {DemoPath} from '@demo/constants'; +import type {MaskitoTimeMode} from '@maskito/kit'; + +describe('DateTime | dateTimeSeparator', () => { + const dateTimeSeparators = [':', ';_', '_-_', '_at_']; + + dateTimeSeparators.forEach(dateTimeSeparator => { + const testCases: Array<{ + typedDigits: string; + formattedDate: string; + formattedValue: string; + timeMode: MaskitoTimeMode; + }> = [ + { + typedDigits: '522004341', + formattedValue: `05.02.2004${dateTimeSeparator}03:41`, + formattedDate: '05.02.2004', + timeMode: 'HH:MM', + }, + { + typedDigits: '233123434111', + formattedValue: `23.03.1234${dateTimeSeparator}03:41:11`, + formattedDate: '23.03.1234', + timeMode: 'HH:MM:SS', + }, + { + typedDigits: '69200734111111', + formattedValue: `06.09.2007${dateTimeSeparator}03:41:11.111`, + formattedDate: '06.09.2007', + timeMode: 'HH:MM:SS.MSS', + }, + ]; + + describe(`correctly applies "${dateTimeSeparator}" as dateTimeSeparator`, () => { + testCases.forEach( + ({typedDigits, formattedDate, formattedValue, timeMode}) => { + const timeDigitsCount = timeMode.replaceAll(/[:.]/g, '').length; + + beforeEach(() => { + cy.visit( + `/${DemoPath.DateTime}/API?dateTimeSeparator=${encodeURIComponent(dateTimeSeparator)}&timeMode=${encodeURIComponent(timeMode)}`, + ); + cy.get('#demo-content input') + .should('be.visible') + .first() + .focus() + .as('input'); + }); + + it(`${typedDigits} => ${formattedValue} => {backspace} * ${timeDigitsCount} => ${formattedDate}`, () => { + cy.get('@input') + .type(typedDigits) + .should('have.value', formattedValue) + .type('{backspace}'.repeat(timeDigitsCount)) + .should('have.value', formattedDate); + }); + }, + ); + }); + }); +}); diff --git a/projects/demo/src/pages/kit/date-time/date-time-mask-doc.component.ts b/projects/demo/src/pages/kit/date-time/date-time-mask-doc.component.ts index bb657183d..ead832f3a 100644 --- a/projects/demo/src/pages/kit/date-time/date-time-mask-doc.component.ts +++ b/projects/demo/src/pages/kit/date-time/date-time-mask-doc.component.ts @@ -7,12 +7,13 @@ import type {MaskitoDateMode, MaskitoTimeMode} from '@maskito/kit'; import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; import type {TuiDocExample} from '@taiga-ui/addon-doc'; import {TuiAddonDocModule} from '@taiga-ui/addon-doc'; -import {CHAR_NO_BREAK_SPACE, tuiPure} from '@taiga-ui/cdk'; +import {tuiPure} from '@taiga-ui/cdk'; import {TuiLinkModule, TuiTextfieldControllerModule} from '@taiga-ui/core'; -import {TuiInputModule} from '@taiga-ui/kit'; +import {DATE_TIME_SEPARATOR, TuiInputModule} from '@taiga-ui/kit'; import {DateTimeMaskDocExample1} from './examples/1-date-time-localization/component'; -import {DateTimeMaskDocExample2} from './examples/2-min-max/component'; +import {DateTimeMaskDocExample2} from './examples/2-date-time-separator/component'; +import {DateTimeMaskDocExample3} from './examples/3-min-max/component'; type GeneratorOptions = Required< NonNullable[0]> @@ -30,19 +31,26 @@ type GeneratorOptions = Required< TuiTextfieldControllerModule, DateTimeMaskDocExample1, DateTimeMaskDocExample2, + DateTimeMaskDocExample3, ], templateUrl: './date-time-mask-doc.template.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export class DateTimeMaskDocComponent implements GeneratorOptions { - protected readonly dateTimeLocalization: TuiDocExample = { + protected readonly dateTimeLocalizationExample: TuiDocExample = { [DocExamplePrimaryTab.MaskitoOptions]: import( './examples/1-date-time-localization/mask.ts?raw' ), }; - protected readonly dateTimeMinMax: TuiDocExample = { - [DocExamplePrimaryTab.MaskitoOptions]: import('./examples/2-min-max/mask.ts?raw'), + protected readonly dateTimeSeparatorExample: TuiDocExample = { + [DocExamplePrimaryTab.MaskitoOptions]: import( + './examples/2-date-time-separator/mask.ts?raw' + ), + }; + + protected readonly dateTimeMinMaxExample: TuiDocExample = { + [DocExamplePrimaryTab.MaskitoOptions]: import('./examples/3-min-max/mask.ts?raw'), }; protected apiPageControl = new FormControl(''); @@ -71,6 +79,7 @@ export class DateTimeMaskDocComponent implements GeneratorOptions { public dateMode: MaskitoDateMode = this.dateModeOptions[0]; public timeMode: MaskitoTimeMode = this.timeModeOptions[0]; + public dateTimeSeparator = DATE_TIME_SEPARATOR; public dateSeparator = '.'; public min = new Date(this.minStr); public max = new Date(this.maxStr); @@ -82,10 +91,9 @@ export class DateTimeMaskDocComponent implements GeneratorOptions { dateMode: MaskitoDateMode, timeMode: MaskitoTimeMode, separator: string, + dateTimeSeparator: string, ): string { - const dateTimeSep = `,${CHAR_NO_BREAK_SPACE}`; - - return `${dateMode.replaceAll('/', separator)}${dateTimeSep}${timeMode}`; + return `${dateMode.replaceAll('/', separator)}${dateTimeSeparator}${timeMode}`; } protected updateOptions(): void { diff --git a/projects/demo/src/pages/kit/date-time/date-time-mask-doc.template.html b/projects/demo/src/pages/kit/date-time/date-time-mask-doc.template.html index e891d00a5..bb3b68c01 100644 --- a/projects/demo/src/pages/kit/date-time/date-time-mask-doc.template.html +++ b/projects/demo/src/pages/kit/date-time/date-time-mask-doc.template.html @@ -10,7 +10,7 @@ @@ -25,10 +25,24 @@ + + + Use + dateTimeSeparator + parameter to configure separator between date and time strings. + + + + @@ -47,7 +61,7 @@ . - + @@ -57,7 +71,7 @@ Enter date and time + + Separator between date and time + +

+ Default: + + (comma and space) +

+
+ + Custom date and time separator + +
+ `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DateTimeMaskDocExample2 { + protected value = '05.02.2004; 10:10'; + protected readonly filler = 'dd.mm.yyyy; hh:mm'; + protected readonly mask = mask; +} diff --git a/projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/mask.ts b/projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/mask.ts new file mode 100644 index 000000000..a2daa4465 --- /dev/null +++ b/projects/demo/src/pages/kit/date-time/examples/2-date-time-separator/mask.ts @@ -0,0 +1,7 @@ +import {maskitoDateTimeOptionsGenerator} from '@maskito/kit'; + +export default maskitoDateTimeOptionsGenerator({ + dateMode: 'dd/mm/yyyy', + timeMode: 'HH:MM', + dateTimeSeparator: '; ', +}); diff --git a/projects/demo/src/pages/kit/date-time/examples/2-min-max/component.ts b/projects/demo/src/pages/kit/date-time/examples/3-min-max/component.ts similarity index 92% rename from projects/demo/src/pages/kit/date-time/examples/2-min-max/component.ts rename to projects/demo/src/pages/kit/date-time/examples/3-min-max/component.ts index 9a21b361f..e05a08a10 100644 --- a/projects/demo/src/pages/kit/date-time/examples/2-min-max/component.ts +++ b/projects/demo/src/pages/kit/date-time/examples/3-min-max/component.ts @@ -8,7 +8,7 @@ import mask from './mask'; @Component({ standalone: true, - selector: 'date-time-mask-doc-example-2', + selector: 'date-time-mask-doc-example-3', imports: [ TuiInputModule, TuiTextfieldControllerModule, @@ -32,7 +32,7 @@ import mask from './mask'; `, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DateTimeMaskDocExample2 { +export class DateTimeMaskDocExample3 { protected value = '09-01-2018, 15:30'; protected readonly filler = 'dd-mm-yyyy, hh:mm'; protected readonly mask = mask; diff --git a/projects/demo/src/pages/kit/date-time/examples/2-min-max/mask.ts b/projects/demo/src/pages/kit/date-time/examples/3-min-max/mask.ts similarity index 100% rename from projects/demo/src/pages/kit/date-time/examples/2-min-max/mask.ts rename to projects/demo/src/pages/kit/date-time/examples/3-min-max/mask.ts diff --git a/projects/kit/src/lib/masks/date-range/processors/min-max-range-length-postprocessor.ts b/projects/kit/src/lib/masks/date-range/processors/min-max-range-length-postprocessor.ts index 2e43ed735..29e668d93 100644 --- a/projects/kit/src/lib/masks/date-range/processors/min-max-range-length-postprocessor.ts +++ b/projects/kit/src/lib/masks/date-range/processors/min-max-range-length-postprocessor.ts @@ -70,7 +70,9 @@ export function createMinMaxRangeLengthPostprocessor({ value: dateStrings[0] + rangeSeparator + - toDateString(dateToSegments(minMaxLengthClampedToDate), dateModeTemplate), + toDateString(dateToSegments(minMaxLengthClampedToDate), { + dateMode: dateModeTemplate, + }), }; }; } diff --git a/projects/kit/src/lib/masks/date-time/date-time-mask.ts b/projects/kit/src/lib/masks/date-time/date-time-mask.ts index 2452d4061..2cad6759b 100644 --- a/projects/kit/src/lib/masks/date-time/date-time-mask.ts +++ b/projects/kit/src/lib/masks/date-time/date-time-mask.ts @@ -11,7 +11,7 @@ import { normalizeDatePreprocessor, } from '../../processors'; import type {MaskitoDateMode, MaskitoTimeMode} from '../../types'; -import {DATE_TIME_SEPARATOR, POSSIBLE_DATE_TIME_SEPARATOR} from './constants'; +import {DATE_TIME_SEPARATOR} from './constants'; import {createMinMaxDateTimePostprocessor} from './postprocessors'; import {createValidDateTimePreprocessor} from './preprocessors'; import {parseDateTimeString} from './utils'; @@ -22,12 +22,14 @@ export function maskitoDateTimeOptionsGenerator({ dateSeparator = '.', min, max, + dateTimeSeparator = DATE_TIME_SEPARATOR, }: { dateMode: MaskitoDateMode; timeMode: MaskitoTimeMode; dateSeparator?: string; max?: Date; min?: Date; + dateTimeSeparator?: string; }): Required { const dateModeTemplate = dateMode.split('/').join(dateSeparator); @@ -37,7 +39,7 @@ export function maskitoDateTimeOptionsGenerator({ ...Array.from(dateModeTemplate).map(char => char === dateSeparator ? char : /\d/, ), - ...DATE_TIME_SEPARATOR.split(''), + ...dateTimeSeparator.split(''), ...Array.from(timeMode).map(char => TIME_FIXED_CHARACTERS.includes(char) ? char : /\d/, ), @@ -49,17 +51,19 @@ export function maskitoDateTimeOptionsGenerator({ createFirstDateEndSeparatorPreprocessor({ dateModeTemplate, dateSegmentSeparator: dateSeparator, - firstDateEndSeparator: DATE_TIME_SEPARATOR, - pseudoFirstDateEndSeparators: POSSIBLE_DATE_TIME_SEPARATOR, + firstDateEndSeparator: dateTimeSeparator, + pseudoFirstDateEndSeparators: dateTimeSeparator.split(''), }), createZeroPlaceholdersPreprocessor(), normalizeDatePreprocessor({ dateModeTemplate, dateSegmentsSeparator: dateSeparator, + dateTimeSeparator, }), createValidDateTimePreprocessor({ dateModeTemplate, dateSegmentsSeparator: dateSeparator, + dateTimeSeparator, }), ], postprocessors: [ @@ -67,24 +71,23 @@ export function maskitoDateTimeOptionsGenerator({ dateModeTemplate, dateSegmentSeparator: dateSeparator, splitFn: value => { - const [dateString, timeString] = parseDateTimeString( - value, + const [dateString, timeString] = parseDateTimeString(value, { dateModeTemplate, - ); + dateTimeSeparator, + }); return {dateStrings: [dateString], restPart: timeString}; }, uniteFn: ([validatedDateString], initialValue) => validatedDateString + - (initialValue.includes(DATE_TIME_SEPARATOR) - ? DATE_TIME_SEPARATOR - : ''), + (initialValue.includes(dateTimeSeparator) ? dateTimeSeparator : ''), }), createMinMaxDateTimePostprocessor({ min, max, dateModeTemplate, timeMode, + dateTimeSeparator, }), ], }; diff --git a/projects/kit/src/lib/masks/date-time/postprocessors/min-max-date-time-postprocessor.ts b/projects/kit/src/lib/masks/date-time/postprocessors/min-max-date-time-postprocessor.ts index 379587f4a..61a807fd5 100644 --- a/projects/kit/src/lib/masks/date-time/postprocessors/min-max-date-time-postprocessor.ts +++ b/projects/kit/src/lib/masks/date-time/postprocessors/min-max-date-time-postprocessor.ts @@ -19,18 +19,29 @@ export function createMinMaxDateTimePostprocessor({ timeMode, min = DEFAULT_MIN_DATE, max = DEFAULT_MAX_DATE, + dateTimeSeparator, }: { dateModeTemplate: string; timeMode: MaskitoTimeMode; min?: Date; max?: Date; + dateTimeSeparator: string; }): MaskitoPostprocessor { return ({value, selection}) => { - const [dateString, timeString] = parseDateTimeString(value, dateModeTemplate); + const [dateString, timeString] = parseDateTimeString(value, { + dateModeTemplate, + dateTimeSeparator, + }); const parsedDate = parseDateString(dateString, dateModeTemplate); const parsedTime = parseTimeString(timeString); - if (!isDateTimeStringComplete(value, dateModeTemplate, timeMode)) { + if ( + !isDateTimeStringComplete(value, { + dateMode: dateModeTemplate, + timeMode, + dateTimeSeparator, + }) + ) { const fixedDate = raiseSegmentValueToMin(parsedDate, dateModeTemplate); const {year, month, day} = isDateStringComplete(dateString, dateModeTemplate) ? dateToSegments(clamp(segmentsToDate(fixedDate), min, max)) @@ -43,8 +54,7 @@ export function createMinMaxDateTimePostprocessor({ day, ...parsedTime, }, - dateModeTemplate, - timeMode, + {dateMode: dateModeTemplate, dateTimeSeparator, timeMode}, ); const tail = value.slice(fixedValue.length); @@ -57,11 +67,11 @@ export function createMinMaxDateTimePostprocessor({ const date = segmentsToDate(parsedDate, parsedTime); const clampedDate = clamp(date, min, max); - const validatedValue = toDateString( - dateToSegments(clampedDate), - dateModeTemplate, + const validatedValue = toDateString(dateToSegments(clampedDate), { + dateMode: dateModeTemplate, + dateTimeSeparator, timeMode, - ); + }); return { selection, diff --git a/projects/kit/src/lib/masks/date-time/preprocessors/valid-date-time-preprocessor.ts b/projects/kit/src/lib/masks/date-time/preprocessors/valid-date-time-preprocessor.ts index 72db0dc25..e504bee13 100644 --- a/projects/kit/src/lib/masks/date-time/preprocessors/valid-date-time-preprocessor.ts +++ b/projects/kit/src/lib/masks/date-time/preprocessors/valid-date-time-preprocessor.ts @@ -3,15 +3,16 @@ import type {MaskitoPreprocessor} from '@maskito/core'; import {DEFAULT_TIME_SEGMENT_MAX_VALUES, TIME_FIXED_CHARACTERS} from '../../../constants'; import {escapeRegExp, validateDateString} from '../../../utils'; import {padTimeSegments, validateTimeString} from '../../../utils/time'; -import {DATE_TIME_SEPARATOR} from '../constants'; import {parseDateTimeString} from '../utils'; export function createValidDateTimePreprocessor({ dateModeTemplate, dateSegmentsSeparator, + dateTimeSeparator, }: { dateModeTemplate: string; dateSegmentsSeparator: string; + dateTimeSeparator: string; }): MaskitoPreprocessor { const invalidCharsRegExp = new RegExp( `[^\\d${TIME_FIXED_CHARACTERS.map(escapeRegExp).join('')}${escapeRegExp( @@ -39,12 +40,12 @@ export function createValidDateTimePreprocessor({ let to = rawTo + data.length; const newPossibleValue = value.slice(0, from) + newCharacters + value.slice(to); - const [dateString, timeString] = parseDateTimeString( - newPossibleValue, + const [dateString, timeString] = parseDateTimeString(newPossibleValue, { dateModeTemplate, - ); + dateTimeSeparator, + }); let validatedValue = ''; - const hasDateTimeSeparator = newPossibleValue.includes(DATE_TIME_SEPARATOR); + const hasDateTimeSeparator = newPossibleValue.includes(dateTimeSeparator); const {validatedDateString, updatedSelection} = validateDateString({ dateString, @@ -66,7 +67,7 @@ export function createValidDateTimePreprocessor({ const {validatedTimeString, updatedTimeSelection} = validateTimeString({ timeString, paddedMaxValues, - offset: validatedValue.length + DATE_TIME_SEPARATOR.length, + offset: validatedValue.length + dateTimeSeparator.length, selection: [from, to], }); @@ -77,7 +78,7 @@ export function createValidDateTimePreprocessor({ to = updatedTimeSelection[1]; validatedValue += hasDateTimeSeparator - ? DATE_TIME_SEPARATOR + validatedTimeString + ? dateTimeSeparator + validatedTimeString : validatedTimeString; const newData = validatedValue.slice(from, to); diff --git a/projects/kit/src/lib/masks/date-time/tests/date-time-separator.spec.ts b/projects/kit/src/lib/masks/date-time/tests/date-time-separator.spec.ts new file mode 100644 index 000000000..6e5325121 --- /dev/null +++ b/projects/kit/src/lib/masks/date-time/tests/date-time-separator.spec.ts @@ -0,0 +1,49 @@ +import {MASKITO_DEFAULT_OPTIONS, maskitoTransform} from '@maskito/core'; + +import type {MaskitoTimeMode} from '../../../types'; +import {maskitoDateTimeOptionsGenerator} from '../date-time-mask'; + +describe('DateTime | dateTimeSeparator', () => { + const dateTimeSeparators = [':', ';_', '_-_', '_at_']; + let options = MASKITO_DEFAULT_OPTIONS; + + dateTimeSeparators.forEach(dateTimeSeparator => { + const testCases: Array<{ + typedDigits: string; + formattedValue: string; + timeMode: MaskitoTimeMode; + }> = [ + { + typedDigits: '050220040341', + formattedValue: `05.02.2004${dateTimeSeparator}03:41`, + timeMode: 'HH:MM', + }, + { + typedDigits: '10062007034111', + formattedValue: `10.06.2007${dateTimeSeparator}03:41:11`, + timeMode: 'HH:MM:SS', + }, + { + typedDigits: '15081999034111111', + formattedValue: `15.08.1999${dateTimeSeparator}03:41:11.111`, + timeMode: 'HH:MM:SS.MSS', + }, + ]; + + describe(`correctly applies "${dateTimeSeparator}" as dateTimeSeparator`, () => { + testCases.forEach(({typedDigits, formattedValue, timeMode}) => { + beforeEach(() => { + options = maskitoDateTimeOptionsGenerator({ + dateMode: 'dd/mm/yyyy', + timeMode, + dateTimeSeparator, + }); + }); + + it(`${typedDigits} => ${formattedValue}`, () => { + expect(maskitoTransform(typedDigits, options)).toBe(formattedValue); + }); + }); + }); + }); +}); diff --git a/projects/kit/src/lib/masks/date-time/utils/is-date-time-string-complete.ts b/projects/kit/src/lib/masks/date-time/utils/is-date-time-string-complete.ts index b3f57ec10..d3e1aa2c1 100644 --- a/projects/kit/src/lib/masks/date-time/utils/is-date-time-string-complete.ts +++ b/projects/kit/src/lib/masks/date-time/utils/is-date-time-string-complete.ts @@ -1,15 +1,23 @@ +import type {MaskitoTimeMode} from '../../../types'; import {DATE_TIME_SEPARATOR} from '../constants'; export function isDateTimeStringComplete( dateTimeString: string, - dateMode: string, - timeMode: string, + { + dateMode, + timeMode, + dateTimeSeparator = DATE_TIME_SEPARATOR, + }: { + dateMode: string; + timeMode: MaskitoTimeMode; + dateTimeSeparator: string; + }, ): boolean { return ( dateTimeString.length >= - dateMode.length + timeMode.length + DATE_TIME_SEPARATOR.length && + dateMode.length + timeMode.length + dateTimeSeparator.length && dateTimeString - .split(DATE_TIME_SEPARATOR)[0] + .split(dateTimeSeparator)[0] .split(/\D/) .every(segment => !segment.match(/^0+$/)) ); diff --git a/projects/kit/src/lib/masks/date-time/utils/parse-date-time-string.ts b/projects/kit/src/lib/masks/date-time/utils/parse-date-time-string.ts index 2a9ef60eb..8981e86b6 100644 --- a/projects/kit/src/lib/masks/date-time/utils/parse-date-time-string.ts +++ b/projects/kit/src/lib/masks/date-time/utils/parse-date-time-string.ts @@ -1,16 +1,20 @@ -import {DATE_TIME_SEPARATOR} from '../constants'; - export function parseDateTimeString( dateTime: string, - dateModeTemplate: string, -): string[] { - const hasSeparator = dateTime.includes(DATE_TIME_SEPARATOR); + { + dateModeTemplate, + dateTimeSeparator, + }: { + dateModeTemplate: string; + dateTimeSeparator: string; + }, +): [date: string, time: string] { + const hasSeparator = dateTime.includes(dateTimeSeparator); return [ dateTime.slice(0, dateModeTemplate.length), dateTime.slice( hasSeparator - ? dateModeTemplate.length + DATE_TIME_SEPARATOR.length + ? dateModeTemplate.length + dateTimeSeparator.length : dateModeTemplate.length, ), ]; diff --git a/projects/kit/src/lib/processors/date-segments-zero-padding-postprocessor.ts b/projects/kit/src/lib/processors/date-segments-zero-padding-postprocessor.ts index 6622901bc..d2deae2b7 100644 --- a/projects/kit/src/lib/processors/date-segments-zero-padding-postprocessor.ts +++ b/projects/kit/src/lib/processors/date-segments-zero-padding-postprocessor.ts @@ -43,7 +43,7 @@ export function createDateSegmentsZeroPaddingPostprocessor({ ); validatedDateStrings.push( - toDateString(validatedDateSegments, dateModeTemplate), + toDateString(validatedDateSegments, {dateMode: dateModeTemplate}), ); }); 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 a9b86eaf4..55bb7fece 100644 --- a/projects/kit/src/lib/processors/min-max-date-postprocessor.ts +++ b/projects/kit/src/lib/processors/min-max-date-postprocessor.ts @@ -39,7 +39,7 @@ export function createMinMaxDatePostprocessor({ if (!isDateStringComplete(dateString, dateModeTemplate)) { const fixedDate = raiseSegmentValueToMin(parsedDate, dateModeTemplate); - const fixedValue = toDateString(fixedDate, dateModeTemplate); + const fixedValue = toDateString(fixedDate, {dateMode: dateModeTemplate}); const tail = dateString.endsWith(dateSegmentSeparator) ? dateSegmentSeparator : ''; @@ -51,7 +51,9 @@ export function createMinMaxDatePostprocessor({ const date = segmentsToDate(parsedDate); const clampedDate = clamp(date, min, max); - validatedValue += toDateString(dateToSegments(clampedDate), dateModeTemplate); + validatedValue += toDateString(dateToSegments(clampedDate), { + dateMode: dateModeTemplate, + }); } return { diff --git a/projects/kit/src/lib/processors/normalize-date-preprocessor.ts b/projects/kit/src/lib/processors/normalize-date-preprocessor.ts index 4d4af18fa..7225b80ee 100644 --- a/projects/kit/src/lib/processors/normalize-date-preprocessor.ts +++ b/projects/kit/src/lib/processors/normalize-date-preprocessor.ts @@ -6,18 +6,20 @@ export function normalizeDatePreprocessor({ dateModeTemplate, dateSegmentsSeparator, rangeSeparator = '', + dateTimeSeparator = DATE_TIME_SEPARATOR, }: { dateModeTemplate: string; dateSegmentsSeparator: string; rangeSeparator?: string; + dateTimeSeparator?: string; }): MaskitoPreprocessor { return ({elementState, data}) => { const separator = rangeSeparator ? new RegExp(`${rangeSeparator}|-`) - : DATE_TIME_SEPARATOR; + : dateTimeSeparator; const possibleDates = data.split(separator); - const dates = data.includes(DATE_TIME_SEPARATOR) + const dates = data.includes(dateTimeSeparator) ? [possibleDates[0]] : possibleDates; @@ -37,8 +39,8 @@ export function normalizeDatePreprocessor({ return { elementState, data: `${newData}${ - data.includes(DATE_TIME_SEPARATOR) - ? DATE_TIME_SEPARATOR + possibleDates[1] || '' + data.includes(dateTimeSeparator) + ? dateTimeSeparator + possibleDates[1] || '' : '' }`, }; diff --git a/projects/kit/src/lib/utils/date/to-date-string.ts b/projects/kit/src/lib/utils/date/to-date-string.ts index 9df218a7e..7483ad92c 100644 --- a/projects/kit/src/lib/utils/date/to-date-string.ts +++ b/projects/kit/src/lib/utils/date/to-date-string.ts @@ -1,6 +1,20 @@ import {DATE_TIME_SEPARATOR} from '../../masks/date-time/constants'; import type {MaskitoDateSegments, MaskitoTimeSegments} from '../../types'; +export function toDateString( + segments: Partial, + options: { + dateMode: string; + }, +): string; +export function toDateString( + segments: Partial, + options: { + dateMode: string; + dateTimeSeparator: string; + timeMode: string; + }, +): string; export function toDateString( { day, @@ -10,12 +24,19 @@ export function toDateString( minutes, seconds, milliseconds, - }: Partial>, - dateMode: string, - timeMode?: string, + }: Partial, + { + dateMode, + dateTimeSeparator = DATE_TIME_SEPARATOR, + timeMode, + }: { + dateMode: string; + dateTimeSeparator?: string; + timeMode?: string; + }, ): string { const safeYear = dateMode.match(/y/g)?.length === 2 ? year?.slice(-2) : year; - const fullMode = dateMode + (timeMode ? DATE_TIME_SEPARATOR + timeMode : ''); + const fullMode = dateMode + (timeMode ? dateTimeSeparator + timeMode : ''); return fullMode .replaceAll(/d+/g, day ?? '') diff --git a/projects/kit/src/lib/utils/date/validate-date-string.ts b/projects/kit/src/lib/utils/date/validate-date-string.ts index 7a0d8b9cf..3387588ef 100644 --- a/projects/kit/src/lib/utils/date/validate-date-string.ts +++ b/projects/kit/src/lib/utils/date/validate-date-string.ts @@ -22,7 +22,9 @@ export function validateDateString({ const validatedDateSegments: Partial = {}; for (const [segmentName, segmentValue] of dateSegments) { - const validatedDate = toDateString(validatedDateSegments, dateModeTemplate); + const validatedDate = toDateString(validatedDateSegments, { + dateMode: dateModeTemplate, + }); const maxSegmentValue = DATE_SEGMENTS_MAX_VALUES[segmentName]; const fantomSeparator = validatedDate.length && 1; @@ -48,7 +50,9 @@ export function validateDateString({ validatedDateSegments[segmentName] = segmentValue; } - const validatedDateString = toDateString(validatedDateSegments, dateModeTemplate); + const validatedDateString = toDateString(validatedDateSegments, { + dateMode: dateModeTemplate, + }); const addedDateSegmentSeparators = validatedDateString.length - dateString.length; return {