Skip to content

Commit

Permalink
feat(kit): Date & DateRange & DateTime has improved zero-paddin…
Browse files Browse the repository at this point in the history
…g support for browser autofill & IME composition (#1027)
  • Loading branch information
nsbarsukov authored Feb 7, 2024
1 parent 4838a2d commit 77ac01c
Show file tree
Hide file tree
Showing 13 changed files with 402 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {DemoPath} from '@demo/constants';

import {BROWSER_SUPPORTS_REAL_EVENTS} from '../../../support/constants';

describe('Date | Date segments zero padding (pads digits with zero if date segment exceeds its max possible value)', () => {
describe('[mode]="dd.mm.yyyy"', () => {
beforeEach(() => {
cy.visit(`/${DemoPath.Date}/API?mode=dd%2Fmm%2Fyyyy&dateSeparator=.`);
cy.get('#demo-content input')
.should('be.visible')
.first()
.focus()
.as('input');
});

describe('pads digit > 3 with zero for days', () => {
[0, 1, 2, 3].forEach(digit => {
it(`Type ${digit} => ${digit}`, () => {
cy.get('@input')
.type(`${digit}`)
.should('have.value', `${digit}`)
.should('have.prop', 'selectionStart', 1)
.should('have.prop', 'selectionEnd', 1);
});
});

[4, 5, 6, 7, 8, 9].forEach(digit => {
it(`Type ${digit} => 0${digit}`, () => {
cy.get('@input')
.type(`${digit}`)
.should('have.value', `0${digit}`)
.should('have.prop', 'selectionStart', `0${digit}`.length)
.should('have.prop', 'selectionEnd', `0${digit}`.length);
});
});

it(
'|11|.11.2011 => Type 7 => 07.|11.2011',
BROWSER_SUPPORTS_REAL_EVENTS,
() => {
cy.get('@input')
.type('11.11.2011')
.type('{moveToStart}')
.realPress(['Shift', 'ArrowRight', 'ArrowRight']);

cy.get('@input')
.should('have.prop', 'selectionStart', 0)
.should('have.prop', 'selectionEnd', '07'.length)
.type('7')
.should('have.value', '07.11.2011')
.should('have.prop', 'selectionStart', '07.'.length)
.should('have.prop', 'selectionEnd', '07.'.length);
},
);
});

describe('pads digit > 1 with zero for months', () => {
[0, 1].forEach(digit => {
it(`Type 01.${digit} => 01.${digit}`, () => {
cy.get('@input')
.type(`01${digit}`)
.should('have.value', `01.${digit}`)
.should('have.prop', 'selectionStart', `01.${digit}`.length)
.should('have.prop', 'selectionEnd', `01.${digit}`.length);
});
});

[2, 3, 4, 5, 6, 7, 8, 9].forEach(digit => {
it(`Type 01.${digit} => 01.0${digit}`, () => {
cy.get('@input')
.type(`01${digit}`)
.should('have.value', `01.0${digit}`)
.should('have.prop', 'selectionStart', `01.0${digit}`.length)
.should('have.prop', 'selectionEnd', `01.0${digit}`.length);
});
});

it(
'11.|11|.2011 => Type 2 => 11.02.|2011',
BROWSER_SUPPORTS_REAL_EVENTS,
() => {
cy.get('@input')
.type('11.11.2011')
.type('{moveToEnd}')
.type('{leftArrow}'.repeat('.2011'.length))
.realPress(['Shift', 'ArrowLeft', 'ArrowLeft']);

cy.get('@input')
.should('have.prop', 'selectionStart', '11.'.length)
.should('have.prop', 'selectionEnd', '11.11'.length)
.type('2')
.should('have.value', '11.02.2011')
.should('have.prop', 'selectionStart', '01.02.'.length)
.should('have.prop', 'selectionEnd', '01.02.'.length);
},
);
});
});
});
7 changes: 7 additions & 0 deletions projects/kit/src/lib/constants/date-segment-max-values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {MaskitoDateSegments} from '../types';

export const DATE_SEGMENTS_MAX_VALUES: MaskitoDateSegments<number> = {
day: 31,
month: 12,
year: 9999,
};
1 change: 1 addition & 0 deletions projects/kit/src/lib/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './date-segment-max-values';
export * from './default-decimal-pseudo-separators';
export * from './default-min-max-dates';
export * from './default-time-segment-max-values';
Expand Down
23 changes: 23 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 @@ -2,12 +2,14 @@ import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions} from '@maskito/core';

import {CHAR_EN_DASH, CHAR_NO_BREAK_SPACE} from '../../constants';
import {
createDateSegmentsZeroPaddingPostprocessor,
createMinMaxDatePostprocessor,
createValidDatePreprocessor,
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
import {MaskitoDateMode, MaskitoDateSegments} from '../../types';
import {parseDateRangeString} from '../../utils';
import {createMinMaxRangeLengthPostprocessor} from './processors/min-max-range-length-postprocessor';
import {createPseudoRangeSeparatorPreprocessor} from './processors/pseudo-range-separator-preprocessor';
import {createSwapDatesPostprocessor} from './processors/swap-dates-postprocessor';
Expand Down Expand Up @@ -53,6 +55,27 @@ export function maskitoDateRangeOptionsGenerator({
}),
],
postprocessors: [
createDateSegmentsZeroPaddingPostprocessor({
dateModeTemplate,
dateSegmentSeparator: dateSeparator,
splitFn: value => ({
dateStrings: parseDateRangeString(
value,
dateModeTemplate,
rangeSeparator,
),
}),
uniteFn: (validatedDateStrings, initialValue) =>
validatedDateStrings.reduce(
(acc, dateString, dateIndex) =>
acc +
dateString +
(!dateIndex && initialValue.includes(rangeSeparator)
? rangeSeparator
: ''),
'',
),
}),
createMinMaxDatePostprocessor({
min,
max,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions, maskitoTransform} from '@maskito/core';
import {maskitoDateRangeOptionsGenerator} from '@maskito/kit';

describe('DateRange (maskitoTransform) | Date segments zero padding', () => {
describe('[mode]="yyyy/mm/dd"', () => {
let options: MaskitoOptions = MASKITO_DEFAULT_OPTIONS;

beforeEach(() => {
options = maskitoDateRangeOptionsGenerator({
mode: 'yyyy/mm/dd',
dateSeparator: '/',
rangeSeparator: '-',
});
});

describe('pads digits with zero if date segment exceeds its max possible value', () => {
describe('pads digit > 1 with zero for months', () => {
[0, 1].forEach(digit => {
it(`1234/${digit} => 1234/${digit}`, () => {
expect(maskitoTransform(`1234${digit}`, options)).toBe(
`1234/${digit}`,
);
expect(
maskitoTransform(`1234/01/01-1234/${digit}`, options),
).toBe(`1234/01/01-1234/${digit}`);
});
});

[2, 3, 4, 5, 6, 7, 8, 9].forEach(digit => {
it(`1234/${digit} => 1234/0${digit}`, () => {
expect(maskitoTransform(`1234${digit}`, options)).toBe(
`1234/0${digit}`,
);
expect(
maskitoTransform(`1234/01/01-1234/${digit}`, options),
).toBe(`1234/01/01-1234/0${digit}`);
});
});
});

describe('pads digit > 3 with zero for days', () => {
[0, 1, 2, 3].forEach(digit => {
it(`1234/12/${digit} => 1234/12/${digit}`, () => {
expect(maskitoTransform(`123412${digit}`, options)).toBe(
`1234/12/${digit}`,
);
expect(
maskitoTransform(`1234/01/01-1234/12/${digit}`, options),
).toBe(`1234/01/01-1234/12/${digit}`);
});
});

[4, 5, 6, 7, 8, 9].forEach(digit => {
it(`1234/12/${digit} => 1234/12/0${digit}`, () => {
expect(maskitoTransform(`123412${digit}`, options)).toBe(
`1234/12/0${digit}`,
);
expect(
maskitoTransform(`1234/01/01-1234/12/${digit}`, options),
).toBe(`1234/01/01-1234/12/0${digit}`);
});
});
});
});
});
});
19 changes: 19 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 @@ -2,13 +2,15 @@ import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions} from '@maskito/core';

import {TIME_FIXED_CHARACTERS} from '../../constants';
import {
createDateSegmentsZeroPaddingPostprocessor,
createZeroPlaceholdersPreprocessor,
normalizeDatePreprocessor,
} from '../../processors';
import {MaskitoDateMode, MaskitoTimeMode} from '../../types';
import {DATE_TIME_SEPARATOR} from './constants';
import {createMinMaxDateTimePostprocessor} from './postprocessors';
import {createValidDateTimePreprocessor} from './preprocessors';
import {parseDateTimeString} from './utils';

export function maskitoDateTimeOptionsGenerator({
dateMode,
Expand Down Expand Up @@ -49,6 +51,23 @@ export function maskitoDateTimeOptionsGenerator({
}),
],
postprocessors: [
createDateSegmentsZeroPaddingPostprocessor({
dateModeTemplate,
dateSegmentSeparator: dateSeparator,
splitFn: value => {
const [dateString, timeString] = parseDateTimeString(
value,
dateModeTemplate,
);

return {dateStrings: [dateString], restPart: timeString};
},
uniteFn: ([validatedDateString], initialValue) =>
validatedDateString +
(initialValue.includes(DATE_TIME_SEPARATOR)
? DATE_TIME_SEPARATOR
: ''),
}),
createMinMaxDateTimePostprocessor({
min,
max,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions, maskitoTransform} from '@maskito/core';
import {maskitoDateTimeOptionsGenerator} from '@maskito/kit';

describe('DateTime (maskitoTransform) | Date segments zero padding', () => {
describe('[dateMode]="dd/mm/yyyy" & [timeMode]="HH:MM:SS.MSS"', () => {
let options: MaskitoOptions = MASKITO_DEFAULT_OPTIONS;

beforeEach(() => {
options = maskitoDateTimeOptionsGenerator({
dateMode: 'dd/mm/yyyy',
timeMode: 'HH:MM:SS.MSS',
dateSeparator: '/',
});
});

describe('pads digits with zero if date segment exceeds its max possible value', () => {
describe('pads digit > 1 with zero for months', () => {
[0, 1].forEach(digit => {
it(`01/${digit} => 01/${digit}`, () => {
expect(maskitoTransform(`01${digit}`, options)).toBe(
`01/${digit}`,
);
});
});

[2, 3, 4, 5, 6, 7, 8, 9].forEach(digit => {
it(`01/${digit} => 01/0${digit}`, () => {
expect(maskitoTransform(`01${digit}`, options)).toBe(
`01/0${digit}`,
);
});
});
});

describe('pads digit > 3 with zero for days', () => {
[0, 1, 2, 3].forEach(digit => {
it(`${digit} => ${digit}`, () => {
expect(maskitoTransform(`${digit}`, options)).toBe(`${digit}`);
});
});

[4, 5, 6, 7, 8, 9].forEach(digit => {
it(`${digit} => 0${digit}`, () => {
expect(maskitoTransform(`${digit}`, options)).toBe(`0${digit}`);
});
});
});
});
});
});
7 changes: 7 additions & 0 deletions projects/kit/src/lib/masks/date/date-mask.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions} from '@maskito/core';

import {
createDateSegmentsZeroPaddingPostprocessor,
createMinMaxDatePostprocessor,
createValidDatePreprocessor,
createZeroPlaceholdersPreprocessor,
Expand Down Expand Up @@ -39,6 +40,12 @@ export function maskitoDateOptionsGenerator({
}),
],
postprocessors: [
createDateSegmentsZeroPaddingPostprocessor({
dateModeTemplate,
dateSegmentSeparator: separator,
splitFn: value => ({dateStrings: [value]}),
uniteFn: ([dateString]) => dateString,
}),
createMinMaxDatePostprocessor({
min,
max,
Expand Down
51 changes: 48 additions & 3 deletions projects/kit/src/lib/masks/date/tests/date-mask.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,54 @@ describe('Date (maskitoTransform)', () => {
});
});

// TODO: fix this bug later
xit('pads digit > 1 with zero for months (12345 => 1234/05)', () => {
expect(maskitoTransform('12345', options)).toBe('1234/05');
describe('pads digits with zero if date segment exceeds its max possible value', () => {
describe('pads digit > 1 with zero for months', () => {
[0, 1].forEach(digit => {
it(`1234/${digit} => 1234/${digit}`, () => {
expect(maskitoTransform(`1234${digit}`, options)).toBe(
`1234/${digit}`,
);
expect(maskitoTransform(`1234/${digit}`, options)).toBe(
`1234/${digit}`,
);
});
});

[2, 3, 4, 5, 6, 7, 8, 9].forEach(digit => {
it(`1234/${digit} => 1234/0${digit}`, () => {
expect(maskitoTransform(`1234${digit}`, options)).toBe(
`1234/0${digit}`,
);
expect(maskitoTransform(`1234/${digit}`, options)).toBe(
`1234/0${digit}`,
);
});
});
});

describe('pads digit > 3 with zero for days', () => {
[0, 1, 2, 3].forEach(digit => {
it(`1234/12/${digit} => 1234/12/${digit}`, () => {
expect(maskitoTransform(`123412${digit}`, options)).toBe(
`1234/12/${digit}`,
);
expect(maskitoTransform(`1234/12/${digit}`, options)).toBe(
`1234/12/${digit}`,
);
});
});

[4, 5, 6, 7, 8, 9].forEach(digit => {
it(`1234/12/${digit} => 1234/12/0${digit}`, () => {
expect(maskitoTransform(`123412${digit}`, options)).toBe(
`1234/12/0${digit}`,
);
expect(maskitoTransform(`1234/12/${digit}`, options)).toBe(
`1234/12/0${digit}`,
);
});
});
});
});

// TODO: https://github.com/taiga-family/maskito/pull/907
Expand Down
Loading

0 comments on commit 77ac01c

Please sign in to comment.