Skip to content

Commit

Permalink
fix(kit): Date accept single character date segment during paste (#610
Browse files Browse the repository at this point in the history
)
  • Loading branch information
vladimirpotekhin authored Oct 19, 2023
1 parent 77a81d1 commit e493198
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 1 deletion.
6 changes: 6 additions & 0 deletions projects/kit/src/lib/masks/date-range/date-range-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
createMinMaxDatePostprocessor,
createValidDatePreprocessor,
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
import {MaskitoDateMode, MaskitoDateSegments} from '../../types';
import {createMinMaxRangeLengthPostprocessor} from './processors/min-max-range-length-postprocessor';
Expand Down Expand Up @@ -44,6 +45,11 @@ export function maskitoDateRangeOptionsGenerator({
overwriteMode: 'replace',
preprocessors: [
createZeroPlaceholdersPreprocessor(),
normalizeDatePreprocessor({
dateModeTemplate,
rangeSeparator,
dateSegmentsSeparator: dateSeparator,
}),
createValidDatePreprocessor({
dateModeTemplate,
rangeSeparator,
Expand Down
9 changes: 8 additions & 1 deletion projects/kit/src/lib/masks/date-time/date-time-mask.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions} from '@maskito/core';

import {TIME_FIXED_CHARACTERS} from '../../constants';
import {createZeroPlaceholdersPreprocessor} from '../../processors';
import {
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
import {MaskitoDateMode, MaskitoTimeMode} from '../../types';
import {DATE_TIME_SEPARATOR} from './constants';
import {createMinMaxDateTimePostprocessor} from './postprocessors';
Expand Down Expand Up @@ -36,6 +39,10 @@ export function maskitoDateTimeOptionsGenerator({
overwriteMode: 'replace',
preprocessors: [
createZeroPlaceholdersPreprocessor(),
normalizeDatePreprocessor({
dateModeTemplate,
dateSegmentsSeparator: dateSeparator,
}),
createValidDateTimePreprocessor({
dateModeTemplate,
dateSegmentsSeparator: dateSeparator,
Expand Down
5 changes: 5 additions & 0 deletions projects/kit/src/lib/masks/date/date-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
createMinMaxDatePostprocessor,
createValidDatePreprocessor,
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
import {MaskitoDateMode} from '../../types';

Expand All @@ -28,6 +29,10 @@ export function maskitoDateOptionsGenerator({
overwriteMode: 'replace',
preprocessors: [
createZeroPlaceholdersPreprocessor(),
normalizeDatePreprocessor({
dateModeTemplate,
dateSegmentsSeparator: separator,
}),
createValidDatePreprocessor({
dateModeTemplate,
dateSegmentsSeparator: separator,
Expand Down
1 change: 1 addition & 0 deletions projects/kit/src/lib/processors/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export {createMinMaxDatePostprocessor} from './min-max-date-postprocessor';
export {normalizeDatePreprocessor} from './normalize-date-preprocessor';
export {maskitoPostfixPostprocessorGenerator} from './postfix-postprocessor';
export {maskitoPrefixPostprocessorGenerator} from './prefix-postprocessor';
export {createValidDatePreprocessor} from './valid-date-preprocessor';
Expand Down
65 changes: 65 additions & 0 deletions projects/kit/src/lib/processors/normalize-date-preprocessor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {MaskitoPreprocessor} from '@maskito/core';

import {DATE_TIME_SEPARATOR} from '../masks/date-time/constants';

export function normalizeDatePreprocessor({
dateModeTemplate,
dateSegmentsSeparator,
rangeSeparator = '',
}: {
dateModeTemplate: string;
dateSegmentsSeparator: string;
rangeSeparator?: string;
}): MaskitoPreprocessor {
return ({elementState, data}) => {
const separator = rangeSeparator
? new RegExp(`${rangeSeparator}|-`)
: DATE_TIME_SEPARATOR;
const possibleDates = data.split(separator);

const dates = data.includes(DATE_TIME_SEPARATOR)
? [possibleDates[0]]
: possibleDates;

if (
dates.every(
date =>
date.trim().split(/\D/).length ===
dateModeTemplate.split(dateSegmentsSeparator).length,
)
) {
const newData = dates
.map(date =>
normalizeDateString(date, dateModeTemplate, dateSegmentsSeparator),
)
.join(rangeSeparator);

return {
elementState,
data: `${newData}${
data.includes(DATE_TIME_SEPARATOR)
? DATE_TIME_SEPARATOR + possibleDates[1] || ''
: ''
}`,
};
}

return {elementState, data};
};
}

function normalizeDateString(
dateString: string,
template: string,
separator: string,
): string {
const dateSegments = dateString.split(/\D/);
const templateSegments = template.split(separator);
const normalizedSegments = dateSegments.map((segment, index) =>
index === templateSegments.length - 1
? segment
: segment.padStart(templateSegments[index].length, '0'),
);

return normalizedSegments.join(separator);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import {MaskitoPreprocessor} from '@maskito/core';

import {normalizeDatePreprocessor} from '../normalize-date-preprocessor';

describe('normalizeDatePreprocessor', () => {
describe('Input-date-range', () => {
const preprocessor = normalizeDatePreprocessor({
dateModeTemplate: 'dd.mm.yyyy',
dateSegmentsSeparator: '.',
rangeSeparator: ' – ',
});

const check = getCheckFunction(preprocessor);

it('Empty input => 6.2.2023 – 7.2.2023', () => {
check('6.2.2023 – 7.2.2023', '06.02.2023 – 07.02.2023');
});

it('Empty input => 6.2.2023 – 7.2.2023 (basic spaces)', () => {
check('6.2.2023 – 7.2.2023', '06.02.2023 – 07.02.2023');
});

it('Empty input => 06.2.2023-07.2.2023', () => {
check('06.2.2023-07.2.2023', '06.02.2023 – 07.02.2023');
});
});

describe('Input-date long mode', () => {
const preprocessor = normalizeDatePreprocessor({
dateModeTemplate: 'dd.mm.yyyy',
dateSegmentsSeparator: '.',
});

const check = getCheckFunction(preprocessor);

it('Empty input => 6.2.2023', () => {
check('6.2.2023', '06.02.2023');
});

it('Empty input => 06.2.2023', () => {
check('06.2.2023', '06.02.2023');
});

it('Empty input => 06.2.20', () => {
check('06.2.20', '06.02.20');
});
});

describe('input-date short mode', () => {
const preprocessor = normalizeDatePreprocessor({
dateModeTemplate: 'mm/yy',
dateSegmentsSeparator: '/',
});

const check = getCheckFunction(preprocessor);

it('Empty input => 2/2/22', () => {
check('2/2', '02/2');
});

it('Empty input => 1.1', () => {
check('1.1', '01/1');
});

it('Empty input => 3.12', () => {
check('3.12', '03/12');
});
});

describe('input-date-time', () => {
const preprocessor = normalizeDatePreprocessor({
dateModeTemplate: 'dd.mm.yyyy',
dateSegmentsSeparator: '.',
});
const check = getCheckFunction(preprocessor);

it('Empty input => 6.2.2023, 12:00', () => {
check('6.2.2023, 12:00', '06.02.2023, 12:00');
});

it('Empty input => 6.2.2023, 15', () => {
check('6.2.2023, 15', '06.02.2023, 15');
});

it('Empty input => 06.2.2023', () => {
check('06.2.2023', '06.02.2023');
});

it('Empty input => 6.2.2023', () => {
check('6.2.2022, 15', '06.02.2022, 15');
});
});
});

function getCheckFunction(
preprocessor: MaskitoPreprocessor,
): (actual: string, expected: string) => void {
return (insertedCharacters: string, expectedValue: string): void => {
const EMPTY_INPUT = {value: '', selection: [0, 0] as [number, number]};

const {data} = preprocessor(
{elementState: EMPTY_INPUT, data: insertedCharacters},
'insert',
);

expect(data).toEqual(expectedValue);
};
}

0 comments on commit e493198

Please sign in to comment.