Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(kit): Date, DateRange, DateTime supports multi-character date segments separator #1306

Merged
merged 1 commit into from
Jun 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
import {
maskitoDateOptionsGenerator,
maskitoDateRangeOptionsGenerator,
maskitoDateTimeOptionsGenerator,
} from '@maskito/kit';

import {TestInput} from '../utils';

describe('Multi character date segment separator', () => {
const multiCharacterSeparator = '. '; // Slovenia;

[
{
title: 'Date',
maskitoOptions: maskitoDateOptionsGenerator({
mode: 'dd/mm/yyyy',
separator: multiCharacterSeparator,
}),
initialValue: '',
},
{
title: 'DateRange (1st date)',
maskitoOptions: maskitoDateRangeOptionsGenerator({
mode: 'dd/mm/yyyy',
dateSeparator: multiCharacterSeparator,
}),
initialValue: '',
},
{
title: 'DateRange (2nd date)',
maskitoOptions: maskitoDateRangeOptionsGenerator({
mode: 'dd/mm/yyyy',
rangeSeparator: '_',
dateSeparator: multiCharacterSeparator,
}),
initialValue: '12. 04. 1961_',
},
{
title: 'DateTime',
maskitoOptions: maskitoDateTimeOptionsGenerator({
dateMode: 'dd/mm/yyyy',
timeMode: 'HH:MM',
dateSeparator: multiCharacterSeparator,
}),
initialValue: '',
},
].forEach(({title, maskitoOptions, initialValue}) => {
describe(title, () => {
beforeEach(() => {
cy.mount(TestInput, {
componentProperties: {
maskitoOptions,
initialValue,
},
});
cy.get('input')
.focus()
.should('have.value', initialValue)
.type('{moveToEnd}');
});

it('Type 31121999 => 31. 12. 1999', () => {
cy.get('input')
.type('31121999')
.should('have.value', `${initialValue}31. 12. 1999`);
});

it('Type 999 => 09. 09. 9 (zero padding works)', () => {
cy.get('input')
.type('999')
.should('have.value', `${initialValue}09. 09. 9`);
});

it('Type 35 => 3 (prevent to enter impossible day date segment)', () => {
cy.get('input').type('35').should('have.value', `${initialValue}3`);
});

it('Type 31.15 => 31.1 (prevent to enter impossible month date segment)', () => {
cy.get('input').type('3115').should('have.value', `${initialValue}31. 1`);
});

describe('Editing somewhere in the middle of a value (NOT the last character)', () => {
it('01.1|2.1998 => Backspace => 01.|02.1998 => Type "1" => 01.1|2.1998', () => {
cy.get('input')
.type('01121998')
.type('{leftArrow}'.repeat('2. 1998'.length))
.should(
'have.prop',
'selectionStart',
`${initialValue}01. 1`.length,
)
.should(
'have.prop',
'selectionEnd',
`${initialValue}01. 1`.length,
)
.type('{backspace}')
.should('have.value', `${initialValue}01. 02. 1998`)
.should(
'have.prop',
'selectionStart',
`${initialValue}01. `.length,
)
.should('have.prop', 'selectionEnd', `${initialValue}01. `.length)
.type('1')
.should('have.value', `${initialValue}01. 12. 1998`)
.should(
'have.prop',
'selectionStart',
`${initialValue}01. 1`.length,
)
.should(
'have.prop',
'selectionEnd',
`${initialValue}01. 1`.length,
);
});

it('12|.01.2008 => Backspace => 1|0.01.2008 => Type "1" => 11|.01.2008', () => {
cy.get('input')
.type('12012008')
.type('{leftArrow}'.repeat(' .01 .2008'.length))
.should('have.prop', 'selectionStart', `${initialValue}12`.length)
.should('have.prop', 'selectionEnd', `${initialValue}12`.length)
.type('{backspace}')
.should('have.value', `${initialValue}10. 01. 2008`)
.should('have.prop', 'selectionStart', `${initialValue}1`.length)
.should('have.prop', 'selectionEnd', `${initialValue}1`.length)
.type('1')
.should('have.value', `${initialValue}11. 01. 2008`)
.should(
'have.prop',
'selectionStart',
`${initialValue}11. `.length,
)
.should(
'have.prop',
'selectionEnd',
`${initialValue}11. `.length,
);
});

it('12.|12.2010 => Type "9" => 12.09.|2010', () => {
cy.get('input')
.type('12122010')
.type('{leftArrow}'.repeat('12. 2010'.length))
.should(
'have.prop',
'selectionStart',
`${initialValue}12. `.length,
)
.should('have.prop', 'selectionEnd', `${initialValue}12. `.length)
.type('9')
.should('have.value', `${initialValue}12. 09. 2010`)
.should(
'have.prop',
'selectionStart',
`${initialValue}12. 09. `.length,
)
.should(
'have.prop',
'selectionEnd',
`${initialValue}12. 09. `.length,
);
});

it('|15.01.2012 => Type "3" => 3|0.01.2012', () => {
cy.get('input')
.type('15012012')
.type('{leftArrow}'.repeat('15. 01. 2012'.length))
.should('have.prop', 'selectionStart', initialValue.length)
.should('have.prop', 'selectionEnd', initialValue.length)
.type('3')
.should('have.value', `${initialValue}30. 01. 2012`)
.should('have.prop', 'selectionStart', `${initialValue}3`.length)
.should('have.prop', 'selectionEnd', `${initialValue}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', `${initialValue}02`.length)
.should('have.prop', 'selectionEnd', `${initialValue}02`.length)
.type('{backspace}')
.should('have.value', `${initialValue}01. 01. 2008`)
.should('have.prop', 'selectionStart', `${initialValue}0`.length)
.should('have.prop', 'selectionEnd', `${initialValue}0`.length)
.type('5')
.should('have.value', `${initialValue}05. 01. 2008`)
.should(
'have.prop',
'selectionStart',
`${initialValue}05. `.length,
)
.should(
'have.prop',
'selectionEnd',
`${initialValue}05. `.length,
);
});
});
});
});
});
2 changes: 1 addition & 1 deletion projects/kit/src/lib/masks/date-range/date-range-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function maskitoDateRangeOptionsGenerator({
}): Required<MaskitoOptions> {
const dateModeTemplate = mode.split('/').join(dateSeparator);
const dateMask = Array.from(dateModeTemplate).map(char =>
char === dateSeparator ? char : /\d/,
dateSeparator.includes(char) ? char : /\d/,
);

return {
Expand Down
2 changes: 1 addition & 1 deletion projects/kit/src/lib/masks/date-time/date-time-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function maskitoDateTimeOptionsGenerator({
...MASKITO_DEFAULT_OPTIONS,
mask: [
...Array.from(dateModeTemplate).map(char =>
char === dateSeparator ? char : /\d/,
dateSeparator.includes(char) ? char : /\d/,
),
...dateTimeSeparator.split(''),
...Array.from(timeMode).map(char =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export function createValidDateTimePreprocessor({

const {validatedDateString, updatedSelection} = validateDateString({
dateString,
dateSegmentsSeparator,
dateModeTemplate,
offset: 0,
selection: [from, to],
Expand Down
2 changes: 1 addition & 1 deletion projects/kit/src/lib/masks/date/date-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function maskitoDateOptionsGenerator({
return {
...MASKITO_DEFAULT_OPTIONS,
mask: Array.from(dateModeTemplate).map(char =>
char === separator ? char : /\d/,
separator.includes(char) ? char : /\d/,
),
overwriteMode: 'replace',
preprocessors: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,19 @@ export function createDateSegmentsZeroPaddingPostprocessor({
: '') +
restPart;

if (caretShift && validatedValue[to + 1] === dateSegmentSeparator) {
if (
caretShift &&
validatedValue.slice(
to + caretShift,
to + caretShift + dateSegmentSeparator.length,
) === dateSegmentSeparator
) {
/**
* If `caretShift` > 0, it means that time segment was padded with zero.
* It is only possible if any character insertion happens.
* If caret is before `dateSegmentSeparator` => it should be moved after `dateSegmentSeparator`.
*/
caretShift++;
caretShift += dateSegmentSeparator.length;
}

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ export function createValidDatePreprocessor({
const {validatedDateString, updatedSelection} = validateDateString({
dateString,
dateModeTemplate,
dateSegmentsSeparator,
offset: validatedValue.length,
selection: [from, to],
});
Expand Down
4 changes: 3 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 @@ -7,10 +7,12 @@ import {toDateString} from './to-date-string';
export function validateDateString({
dateString,
dateModeTemplate,
dateSegmentsSeparator,
offset,
selection: [from, to],
}: {
dateString: string;
dateSegmentsSeparator: string;
dateModeTemplate: string;
offset: number;
selection: [number, number];
Expand All @@ -27,7 +29,7 @@ export function validateDateString({
});
const maxSegmentValue = DATE_SEGMENTS_MAX_VALUES[segmentName];

const fantomSeparator = validatedDate.length && 1;
const fantomSeparator = validatedDate.length && dateSegmentsSeparator.length;

const lastSegmentDigitIndex =
offset +
Expand Down
Loading