Skip to content

Commit

Permalink
feat(kit): use 1 as min segment value in Date-related masks (#197)
Browse files Browse the repository at this point in the history
  • Loading branch information
vladimirpotekhin authored Mar 16, 2023
1 parent 0853483 commit c85ca23
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,15 @@ describe('DateRange | Basic', () => {
.should('have.prop', 'selectionEnd', '25.02.18'.length);
});

it('13.06.1736 - 14.09|.1821 => Backspace => 13.06.1736 - 14.0|0.1821 => Type "3" => 13.06.1736 - 14.03|.1821', () => {
it('13.06.1736 - 14.09|.1821 => Backspace => 13.06.1736 - 14.0|1.1821 => Type "3" => 13.06.1736 - 14.03|.1821', () => {
cy.get('@input')
.type('13.06.1736-14.09.1821')
.should('have.value', '13.06.1736 – 14.09.1821')
.type('{leftArrow}'.repeat('.1821'.length))
.should('have.prop', 'selectionStart', '13.06.1736 - 14.09'.length)
.should('have.prop', 'selectionEnd', '13.06.1736 - 14.09'.length)
.type('{backspace}')
.should('have.value', '13.06.1736 – 14.00.1821')
.should('have.value', '13.06.1736 – 14.01.1821')
.should('have.prop', 'selectionStart', '13.06.1736 - 14.0'.length)
.should('have.prop', 'selectionEnd', '13.06.1736 - 14.0'.length)
.type('3')
Expand Down Expand Up @@ -300,7 +300,7 @@ describe('DateRange | Basic', () => {

describe('Text selection', () => {
describe('Select range and press Backspace / Delete', () => {
it('10.|12|.2005 - 16.12.2007 => Backspace => 10.|00.2005 - 16.12.2007', () => {
it('10.|12|.2005 - 16.12.2007 => Backspace => 10.|01.2005 - 16.12.2007', () => {
cy.get('@input')
.type('10122005-16122007')
.should('have.value', '10.12.2005 – 16.12.2007')
Expand All @@ -312,12 +312,12 @@ describe('DateRange | Basic', () => {
]);

cy.get('@input')
.should('have.value', '10.00.2005 – 16.12.2007')
.should('have.value', '10.01.2005 – 16.12.2007')
.should('have.prop', 'selectionStart', '10.'.length)
.should('have.prop', 'selectionEnd', '10.'.length);
});

it('10.12.2005 - |16|.12.2007 => Backspace => 10.12.2005 - |00.12.2007', () => {
it('10.12.2005 - |16|.12.2007 => Backspace => 10.12.2005 - |01.12.2007', () => {
cy.get('@input')
.type('10122005-16122007')
.should('have.value', '10.12.2005 – 16.12.2007')
Expand All @@ -329,7 +329,7 @@ describe('DateRange | Basic', () => {
]);

cy.get('@input')
.should('have.value', '10.12.2005 – 00.12.2007')
.should('have.value', '10.12.2005 – 01.12.2007')
.should('have.prop', 'selectionStart', '10.12.2005 - '.length)
.should('have.prop', 'selectionEnd', '10.12.2005 - '.length);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ describe('DateTime | Basic', () => {
['1811201623152', '18.11.2016, 23:15:2'],
['18112016231522', '18.11.2016, 23:15:22'],
['18112016231522123', '18.11.2016, 23:15:22.123'],
['0', '0'],
['00', '0'],
] as const;

tests.forEach(([typedValue, maskedValue]) => {
Expand Down Expand Up @@ -219,7 +221,7 @@ describe('DateTime | Basic', () => {

describe('Text selection', () => {
describe('Select range and press Backspace / Delete', () => {
it('10.|12|.2005, 12:30 => Backspace => 10.|00.2005, 12:30', () => {
it('10.|12|.2005, 12:30 => Backspace => 10.|01.2005, 12:30', () => {
cy.get('@input')
.type('101220051230')
.should('have.value', '10.12.2005, 12:30')
Expand All @@ -231,7 +233,7 @@ describe('DateTime | Basic', () => {
]);

cy.get('@input')
.should('have.value', '10.00.2005, 12:30')
.should('have.value', '10.01.2005, 12:30')
.should('have.prop', 'selectionStart', '10.'.length)
.should('have.prop', 'selectionEnd', '10.'.length);
});
Expand Down
22 changes: 20 additions & 2 deletions projects/demo-integrations/cypress/tests/kit/date/date-basic.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ describe('Date', () => {
['12', '12', '12'.length],
['121', '12.1', '12.1'.length],
['1211', '12.11', '12.11'.length],
['0', '0', 1],
['00', '0', '0'.length],
] as const;

tests.forEach(([typedValue, maskedValue, caretIndex]) => {
Expand Down Expand Up @@ -176,6 +178,22 @@ describe('Date', () => {
.should('have.prop', 'selectionStart', '3'.length)
.should('have.prop', 'selectionEnd', '3'.length);
});

it('02|.01.2008 => Backspace => 0|1.01.2008 => Type "5" => 05|.01.2008', () => {
cy.get('@input')
.type('02012008')
.type('{leftArrow}'.repeat('.01.2008'.length))
.should('have.prop', 'selectionStart', '02'.length)
.should('have.prop', 'selectionEnd', '02'.length)
.type('{backspace}')
.should('have.value', '01.01.2008')
.should('have.prop', 'selectionStart', '0'.length)
.should('have.prop', 'selectionEnd', '0'.length)
.type('5')
.should('have.value', '05.01.2008')
.should('have.prop', 'selectionStart', '05.'.length)
.should('have.prop', 'selectionEnd', '05.'.length);
});
});

describe('Fixed values', () => {
Expand Down Expand Up @@ -206,7 +224,7 @@ describe('Date', () => {

describe('Text selection', () => {
describe('Select range and press Backspace', () => {
it('10.|12|.2022 => Backspace => 10.|00.2022', () => {
it('10.|12|.2022 => Backspace => 10.|01.2022', () => {
cy.get('@input')
.type('10122022')
.type('{leftArrow}'.repeat('.2022'.length))
Expand All @@ -217,7 +235,7 @@ describe('Date', () => {
]);

cy.get('@input')
.should('have.value', '10.00.2022')
.should('have.value', '10.01.2022')
.should('have.prop', 'selectionStart', '10.'.length)
.should('have.prop', 'selectionEnd', '10.'.length);
});
Expand Down
1 change: 1 addition & 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 @@ -48,6 +48,7 @@ export function maskitoDateRangeOptionsGenerator({
max,
dateModeTemplate,
datesSeparator: DATE_RANGE_SEPARATOR,
dateSegmentSeparator: separator,
}),
createMinMaxRangeLengthPostprocessor({
dateModeTemplate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
segmentsToDate,
toDateString,
} from '../../../utils';
import {raiseSegmentValueToMin} from '../../../utils/date/raise-segment-value-to-min';
import {parseTimeString} from '../../../utils/time';
import {isDateTimeStringComplete, parseDateTimeString} from '../utils';

Expand All @@ -25,16 +26,24 @@ export function createMinMaxDateTimePostprocessor({
}): NonNullable<MaskitoOptions['postprocessor']> {
return ({value, selection}) => {
const [dateString, timeString] = parseDateTimeString(value, dateModeTemplate);
const parsedDate = parseDateString(dateString, dateModeTemplate);
const parsedTime = parseTimeString(timeString);

if (!isDateTimeStringComplete(value, dateModeTemplate, timeMode)) {
const fixedDate = raiseSegmentValueToMin(parsedDate, dateModeTemplate);
const fixedValue = toDateString(
{...fixedDate, ...parsedTime},
dateModeTemplate,
timeMode,
);
const tail = value.slice(fixedValue.length);

return {
selection,
value: value,
value: fixedValue + tail,
};
}

const parsedDate = parseDateString(dateString, dateModeTemplate);
const parsedTime = parseTimeString(timeString);
const date = segmentsToDate(parsedDate, parsedTime);
const clampedDate = clamp(date, min, max);

Expand Down
7 changes: 6 additions & 1 deletion projects/kit/src/lib/masks/date/date-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export function maskitoDateOptionsGenerator({
dateSegmentsSeparator: separator,
}),
),
postprocessor: createMinMaxDatePostprocessor({min, max, dateModeTemplate}),
postprocessor: createMinMaxDatePostprocessor({
min,
max,
dateModeTemplate,
dateSegmentSeparator: separator,
}),
};
}
15 changes: 13 additions & 2 deletions projects/kit/src/lib/processors/min-max-date-postprocessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,20 @@ import {
segmentsToDate,
toDateString,
} from '../utils';
import {raiseSegmentValueToMin} from '../utils/date/raise-segment-value-to-min';

export function createMinMaxDatePostprocessor({
dateModeTemplate,
min = DEFAULT_MIN_DATE,
max = DEFAULT_MAX_DATE,
datesSeparator = '',
dateSegmentSeparator = '.',
}: {
dateModeTemplate: string;
min?: Date;
max?: Date;
datesSeparator?: string;
dateSegmentSeparator?: string;
}): NonNullable<MaskitoOptions['postprocessor']> {
return ({value, selection}) => {
const endsWithDatesSeparator = datesSeparator && value.endsWith(datesSeparator);
Expand All @@ -31,12 +34,20 @@ export function createMinMaxDatePostprocessor({
for (const dateString of dateStrings) {
validatedValue += validatedValue ? datesSeparator : '';

const parsedDate = parseDateString(dateString, dateModeTemplate);

if (!isDateStringComplete(dateString, dateModeTemplate)) {
validatedValue += dateString;
const fixedDate = raiseSegmentValueToMin(parsedDate, dateModeTemplate);

const fixedValue = toDateString(fixedDate, dateModeTemplate);
const tail = dateString.endsWith(dateSegmentSeparator)
? dateSegmentSeparator
: '';

validatedValue += fixedValue + tail;
continue;
}

const parsedDate = parseDateString(dateString, dateModeTemplate);
const date = segmentsToDate(parsedDate);
const clampedDate = clamp(date, min, max);

Expand Down
6 changes: 3 additions & 3 deletions projects/kit/src/lib/utils/date/date-segment-value-length.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {MaskitoDateSegments} from '../../types';
export const getDateSegmentValueLength: (
dateString: string,
) => MaskitoDateSegments<number> = (dateString: string) => ({
day: dateString.match('/d/g')?.length || 2,
month: dateString.match('/m/g')?.length || 2,
year: dateString.match('/y/g')?.length || 4,
day: dateString.match(/d/g)?.length || 0,
month: dateString.match(/m/g)?.length || 0,
year: dateString.match(/y/g)?.length || 0,
});
24 changes: 24 additions & 0 deletions projects/kit/src/lib/utils/date/raise-segment-value-to-min.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {MaskitoDateSegments} from '../../types';
import {getObjectFromEntries} from '../get-object-from-entries';
import {getDateSegmentValueLength} from './date-segment-value-length';

export function raiseSegmentValueToMin(
segments: Partial<MaskitoDateSegments>,
fullMode: string,
): Partial<MaskitoDateSegments> {
const segmentsLength = getDateSegmentValueLength(fullMode);

return getObjectFromEntries(
Object.entries<string>(segments).map(([key, value]: [string, string]) => {
const segmentLength =
segmentsLength[key as keyof Partial<MaskitoDateSegments>];

return [
key,
value.length === segmentLength && value.match(/^0+$/)
? '1'.padStart(segmentLength, '0')
: value,
];
}),
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {getDateSegmentValueLength} from '../date-segment-value-length';

describe('getDateSegmentValueLength', () => {
it('short date', () => {
expect(getDateSegmentValueLength('mm.yy')).toEqual({day: 0, month: 2, year: 2});
});

it('full date', () => {
expect(getDateSegmentValueLength('dd.mm.yyyy')).toEqual({
day: 2,
month: 2,
year: 4,
});
});
});
7 changes: 6 additions & 1 deletion projects/kit/src/lib/utils/date/validate-date-string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function validateDateString({
offset +
validatedDate.length +
fantomSeparator +
getDateSegmentValueLength(dateString)[segmentName];
getDateSegmentValueLength(dateModeTemplate)[segmentName];
const isLastSegmentDigitAdded =
lastSegmentDigitIndex >= from && lastSegmentDigitIndex <= to;

Expand All @@ -48,6 +48,11 @@ export function validateDateString({
return {validatedDateString: '', updatedSelection: [from, to]}; // prevent changes
}

if (isLastSegmentDigitAdded && Number(segmentValue) < 1) {
// 31.0|1.2010 => Type 0 => 31.0|1.2010
return {validatedDateString: '', updatedSelection: [from, to]}; // prevent changes
}

const {validatedSegmentValue, prefixedZeroesCount} = padWithZeroesUntilValid(
segmentValue,
`${maxSegmentValue}`,
Expand Down

0 comments on commit c85ca23

Please sign in to comment.