Skip to content

Commit

Permalink
refactor(kit): simplify some code logic for Time mask (#1688)
Browse files Browse the repository at this point in the history
  • Loading branch information
nsbarsukov authored Sep 25, 2024
1 parent a92e35e commit 8c608b8
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 242 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ describe('Time', () => {
.should('have.prop', 'selectionEnd', '20:0'.length);
});

it('|23|:59 => Delete => 00:|59', BROWSER_SUPPORTS_REAL_EVENTS, () => {
it('|23|:59 => Delete => 00|:59', BROWSER_SUPPORTS_REAL_EVENTS, () => {
cy.get('@input')
.type('2359')
.realPress([
Expand Down
12 changes: 12 additions & 0 deletions projects/kit/src/lib/masks/date-time/date-time-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
createDateSegmentsZeroPaddingPostprocessor,
createFirstDateEndSeparatorPreprocessor,
createFullWidthToHalfWidthPreprocessor,
createInvalidTimeSegmentInsertionPreprocessor,
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
Expand Down Expand Up @@ -63,6 +64,17 @@ export function maskitoDateTimeOptionsGenerator({
dateSegmentsSeparator: dateSeparator,
dateTimeSeparator,
}),
createInvalidTimeSegmentInsertionPreprocessor({
timeMode,
parseValue: (x) => {
const [dateString, timeString] = parseDateTimeString(x, {
dateModeTemplate,
dateTimeSeparator,
});

return {timeString, restValue: dateString + dateTimeSeparator};
},
}),
createValidDateTimePreprocessor({
dateModeTemplate,
dateSegmentsSeparator: dateSeparator,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import type {MaskitoPreprocessor} from '@maskito/core';

import {DEFAULT_TIME_SEGMENT_MAX_VALUES, TIME_FIXED_CHARACTERS} from '../../../constants';
import {TIME_FIXED_CHARACTERS} from '../../../constants';
import type {MaskitoTimeMode} from '../../../types';
import {escapeRegExp, validateDateString} from '../../../utils';
import {padStartTimeSegments, validateTimeString} from '../../../utils/time';
import {enrichTimeSegmentsWithZeroes} from '../../../utils/time';
import {parseDateTimeString} from '../utils';

export function createValidDateTimePreprocessor({
Expand Down Expand Up @@ -66,25 +66,16 @@ export function createValidDateTimePreprocessor({

validatedValue += validatedDateString;

const paddedMaxValues = padStartTimeSegments(DEFAULT_TIME_SEGMENT_MAX_VALUES);
const updatedTimeState = enrichTimeSegmentsWithZeroes(
{value: timeString, selection: [from, to]},
{mode: timeMode},
);

const {validatedTimeString, updatedTimeSelection} = validateTimeString({
timeString,
paddedMaxValues,
offset: validatedValue.length + dateTimeSeparator.length,
selection: [from, to],
timeMode,
});

if (timeString && !validatedTimeString) {
return {elementState, data: ''}; // prevent changes
}

to = updatedTimeSelection[1];
to = updatedTimeState.selection[1];

validatedValue += hasDateTimeSeparator
? dateTimeSeparator + validatedTimeString
: validatedTimeString;
? dateTimeSeparator + updatedTimeState.value
: updatedTimeState.value;

const newData = validatedValue.slice(from, to);

Expand Down
1 change: 0 additions & 1 deletion projects/kit/src/lib/masks/time/processors/index.ts

This file was deleted.

This file was deleted.

This file was deleted.

17 changes: 13 additions & 4 deletions projects/kit/src/lib/masks/time/time-mask.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import type {MaskitoOptions} from '@maskito/core';
import {MASKITO_DEFAULT_OPTIONS} from '@maskito/core';

import {DEFAULT_TIME_SEGMENT_MAX_VALUES, TIME_FIXED_CHARACTERS} from '../../constants';
import {createTimeSegmentsSteppingPlugin} from '../../plugins';
import {
createColonConvertPreprocessor,
createFullWidthToHalfWidthPreprocessor,
createInvalidTimeSegmentInsertionPreprocessor,
createZeroPlaceholdersPreprocessor,
} from '../../processors';
import {createMaxValidationPreprocessor} from './processors';
import {enrichTimeSegmentsWithZeroes} from '../../utils/time';
import type {MaskitoTimeParams} from './time-options';

export function maskitoTimeOptionsGenerator({
Expand All @@ -22,15 +22,24 @@ export function maskitoTimeOptionsGenerator({
};

return {
...MASKITO_DEFAULT_OPTIONS,
mask: Array.from(mode).map((char) =>
TIME_FIXED_CHARACTERS.includes(char) ? char : /\d/,
),
preprocessors: [
createFullWidthToHalfWidthPreprocessor(),
createColonConvertPreprocessor(),
createZeroPlaceholdersPreprocessor(),
createMaxValidationPreprocessor(enrichedTimeSegmentMaxValues, mode),
createInvalidTimeSegmentInsertionPreprocessor({
timeMode: mode,
timeSegmentMaxValues: enrichedTimeSegmentMaxValues,
}),
],
postprocessors: [
(elementState) =>
enrichTimeSegmentsWithZeroes(elementState, {
mode,
timeSegmentMaxValues: enrichedTimeSegmentMaxValues,
}),
],
plugins: [
createTimeSegmentsSteppingPlugin({
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
Expand Up @@ -2,6 +2,7 @@ export {createColonConvertPreprocessor} from './colon-convert-preprocessor';
export {createDateSegmentsZeroPaddingPostprocessor} from './date-segments-zero-padding-postprocessor';
export {createFirstDateEndSeparatorPreprocessor} from './first-date-end-separator-preprocessor';
export {createFullWidthToHalfWidthPreprocessor} from './fullwidth-to-halfwidth-preprocessor';
export {createInvalidTimeSegmentInsertionPreprocessor} from './invalid-time-segment-insertion-preprocessor';
export {createMinMaxDatePostprocessor} from './min-max-date-postprocessor';
export {normalizeDatePreprocessor} from './normalize-date-preprocessor';
export {maskitoPostfixPostprocessorGenerator} from './postfix-postprocessor';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import type {MaskitoPreprocessor} from '@maskito/core';
import type {MaskitoTimeMode, MaskitoTimeSegments} from '@maskito/kit';

import {
DEFAULT_TIME_SEGMENT_MAX_VALUES,
TIME_FIXED_CHARACTERS,
TIME_SEGMENT_VALUE_LENGTHS,
} from '../constants';
import {escapeRegExp} from '../utils';
import {padStartTimeSegments, parseTimeString} from '../utils/time';

/**
* Prevent insertion if any time segment will become invalid
* (and even zero padding won't help with it).
* @example 2|0:00 => Type 9 => 2|0:00
*/
export function createInvalidTimeSegmentInsertionPreprocessor({
timeMode,
timeSegmentMaxValues = DEFAULT_TIME_SEGMENT_MAX_VALUES,
parseValue = (x) => ({timeString: x}),
}: {
timeMode: MaskitoTimeMode;
timeSegmentMaxValues?: MaskitoTimeSegments<number>;
parseValue?: (value: string) => {timeString: string; restValue?: string};
}): MaskitoPreprocessor {
const paddedMaxValues = padStartTimeSegments(timeSegmentMaxValues);
const invalidCharsRegExp = new RegExp(
`[^\\d${TIME_FIXED_CHARACTERS.map(escapeRegExp).join('')}]+`,
);

return ({elementState, data}, actionType) => {
if (actionType !== 'insert') {
return {elementState, data};
}

const {value, selection} = elementState;
const [from, rawTo] = selection;
const newCharacters = data.replace(invalidCharsRegExp, '');
const to = rawTo + newCharacters.length; // to be conformed with `overwriteMode: replace`
const newPossibleValue = value.slice(0, from) + newCharacters + value.slice(to);
const {timeString, restValue = ''} = parseValue(newPossibleValue);
const timeSegments = Object.entries(
parseTimeString(timeString, timeMode),
) as Array<[keyof MaskitoTimeSegments, string]>;

let offset = restValue.length;

for (const [segmentName, segmentValue] of timeSegments) {
const maxSegmentValue = paddedMaxValues[segmentName];
const lastSegmentDigitIndex =
offset + TIME_SEGMENT_VALUE_LENGTHS[segmentName];

if (
lastSegmentDigitIndex >= from &&
lastSegmentDigitIndex <= to &&
Number(segmentValue) > Number(maxSegmentValue)
) {
return {elementState, data: ''}; // prevent insertion
}

offset +=
segmentValue.length +
// any time segment separator
1;
}

return {elementState, data};
};
}
Loading

0 comments on commit 8c608b8

Please sign in to comment.