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): Number has problems when prefix/postfix includes decimalSeparator symbol #816

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
Expand Up @@ -35,8 +35,7 @@ describe('Number | postfix with point', () => {
.should('have.prop', 'selectionEnd', 2);
});

// TODO https://github.com/taiga-family/maskito/issues/703
it.skip('Empty => Type 0.42 => 0.42 lbs.', () => {
it('Empty => Type 0.42 => 0.42 lbs.', () => {
cy.mount(TestInput, {componentProperties: {maskitoOptions}});
cy.get('input')
.type('0')
Expand All @@ -52,8 +51,7 @@ describe('Number | postfix with point', () => {
});
});

// TODO https://github.com/taiga-family/maskito/issues/703
describe.skip('Complex: maskitoCaretGuard + maskitoAddOnFocusPlugin + maskitoRemoveOnBlurPlugin', () => {
describe('Complex: maskitoCaretGuard + maskitoAddOnFocusPlugin + maskitoRemoveOnBlurPlugin', () => {
const postfix = ' lbs.';
const numberOptions = maskitoNumberOptionsGenerator({
postfix,
Expand Down
48 changes: 39 additions & 9 deletions projects/kit/src/lib/masks/number/number-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
createThousandSeparatorPostprocessor,
createZeroPrecisionPreprocessor,
} from './processors';
import {createAffixesFilterPreprocessor} from './processors/affixes-filter-preprocessor';
import {generateMaskExpression, validateDecimalPseudoSeparators} from './utils';

export function maskitoNumberOptionsGenerator({
Expand Down Expand Up @@ -79,21 +80,40 @@ export function maskitoNumberOptionsGenerator({
decimalSeparator,
decimalPseudoSeparators: validatedDecimalPseudoSeparators,
pseudoMinuses,
prefix,
postfix,
}),
createAffixesFilterPreprocessor({prefix, postfix}),
createFullWidthToHalfWidthPreprocessor(),
createPseudoCharactersPreprocessor(CHAR_MINUS, pseudoMinuses),
createPseudoCharactersPreprocessor(
decimalSeparator,
validatedDecimalPseudoSeparators,
),
createPseudoCharactersPreprocessor({
validCharacter: CHAR_MINUS,
pseudoCharacters: pseudoMinuses,
prefix,
postfix,
}),
createPseudoCharactersPreprocessor({
validCharacter: decimalSeparator,
pseudoCharacters: validatedDecimalPseudoSeparators,
prefix,
postfix,
}),
createNotEmptyIntegerPartPreprocessor({decimalSeparator, precision}),
createNonRemovableCharsDeletionPreprocessor({
decimalSeparator,
decimalZeroPadding,
thousandSeparator,
}),
createZeroPrecisionPreprocessor(precision, decimalSeparator),
createRepeatedDecimalSeparatorPreprocessor(decimalSeparator),
createZeroPrecisionPreprocessor({
precision,
decimalSeparator,
prefix,
postfix,
}),
createRepeatedDecimalSeparatorPreprocessor({
decimalSeparator,
prefix,
postfix,
}),
],
postprocessors: [
createMinMaxPostprocessor({decimalSeparator, min, max}),
Expand All @@ -109,12 +129,22 @@ export function maskitoNumberOptionsGenerator({
decimalSeparator,
decimalZeroPadding,
precision,
prefix,
postfix,
}),
],
plugins: [
createLeadingZeroesValidationPlugin(decimalSeparator, thousandSeparator),
createNotEmptyIntegerPlugin(decimalSeparator),
createLeadingZeroesValidationPlugin({
decimalSeparator,
thousandSeparator,
prefix,
postfix,
}),
createNotEmptyIntegerPlugin({
decimalSeparator,
prefix,
postfix,
}),
createMinMaxPlugin({min, max, decimalSeparator}),
],
overwriteMode: decimalZeroPadding
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,23 @@ const DUMMY_SELECTION = [0, 0] as const;
* @example 000000 => blur => 0
* @example 00005 => blur => 5
*/
export function createLeadingZeroesValidationPlugin(
decimalSeparator: string,
thousandSeparator: string,
): MaskitoPlugin {
const dropRepeatedLeadingZeroes = createLeadingZeroesValidationPostprocessor(
export function createLeadingZeroesValidationPlugin({
decimalSeparator,
thousandSeparator,
prefix,
postfix,
}: {
decimalSeparator: string;
thousandSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPlugin {
const dropRepeatedLeadingZeroes = createLeadingZeroesValidationPostprocessor({
decimalSeparator,
thousandSeparator,
);
prefix,
postfix,
});

return maskitoEventHandler(
'blur',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,36 @@
import {MaskitoPlugin, maskitoUpdateElement} from '@maskito/core';

import {maskitoEventHandler} from '../../../plugins';
import {escapeRegExp} from '../../../utils';
import {escapeRegExp, extractAffixes} from '../../../utils';

/**
* It pads EMPTY integer part with zero if decimal parts exists.
* It works on blur event only!
* @example 1|,23 => Backspace => Blur => 0,23
*/
export function createNotEmptyIntegerPlugin(decimalSeparator: string): MaskitoPlugin {
export function createNotEmptyIntegerPlugin({
decimalSeparator,
prefix,
postfix,
}: {
decimalSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPlugin {
return maskitoEventHandler(
'blur',
element => {
const newValue = element.value.replace(
new RegExp(`^(\\D+)?${escapeRegExp(decimalSeparator)}`),
`$10${decimalSeparator}`,
const {cleanValue, extractedPostfix, extractedPrefix} = extractAffixes(
element.value,
{prefix, postfix},
);
const newValue =
extractedPrefix +
cleanValue.replace(
new RegExp(`^(\\D+)?${escapeRegExp(decimalSeparator)}`),
`$10${decimalSeparator}`,
) +
extractedPostfix;

if (newValue !== element.value) {
maskitoUpdateElement(element, newValue);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {MaskitoPreprocessor} from '@maskito/core';

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

/**
* It drops prefix and postfix from data
* Needed for case, when prefix or postfix contain decimalSeparator, to ignore it in resulting number
* @example User pastes '{prefix}123.45{postfix}' => 123.45
*/
export function createAffixesFilterPreprocessor({
prefix,
postfix,
}: {
prefix: string;
postfix: string;
}): MaskitoPreprocessor {
return ({elementState, data}) => {
const {cleanValue: cleanData} = extractAffixes(data, {
prefix,
postfix,
});

return {
elementState,
data: cleanData,
};
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {MaskitoPostprocessor} from '@maskito/core';

import {escapeRegExp, identity} from '../../../utils';
import {extractAffixes, identity} from '../../../utils';
import {maskitoParseNumber} from '../utils';

/**
Expand All @@ -12,34 +12,38 @@ export function createDecimalZeroPaddingPostprocessor({
decimalSeparator,
precision,
decimalZeroPadding,
prefix,
postfix,
}: {
decimalSeparator: string;
decimalZeroPadding: boolean;
precision: number;
prefix: string;
postfix: string;
}): MaskitoPostprocessor {
if (precision <= 0 || !decimalZeroPadding) {
return identity;
}

const trailingPostfixRegExp = new RegExp(`${escapeRegExp(postfix)}$`);

return ({value, selection}) => {
if (Number.isNaN(maskitoParseNumber(value, decimalSeparator))) {
const {cleanValue, extractedPrefix, extractedPostfix} = extractAffixes(value, {
prefix,
postfix,
});

if (Number.isNaN(maskitoParseNumber(cleanValue, decimalSeparator))) {
return {value, selection};
}

const [integerPart, decimalPart = ''] = value
.replace(trailingPostfixRegExp, '')
.split(decimalSeparator);
const [integerPart, decimalPart = ''] = cleanValue.split(decimalSeparator);

return {
value:
extractedPrefix +
integerPart +
decimalSeparator +
decimalPart.padEnd(precision, '0') +
postfix,
extractedPostfix,
selection,
};
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {MaskitoPreprocessor, maskitoTransform} from '@maskito/core';

import {extractAffixes} from '../../../utils';
import {generateMaskExpression} from '../utils';

/**
Expand All @@ -16,10 +17,14 @@ export function createInitializationOnlyPreprocessor({
decimalSeparator,
decimalPseudoSeparators,
pseudoMinuses,
prefix,
postfix,
}: {
decimalSeparator: string;
decimalPseudoSeparators: readonly string[];
pseudoMinuses: readonly string[];
prefix: string;
postfix: string;
}): MaskitoPreprocessor {
let isInitializationPhase = true;
const cleanNumberMask = generateMaskExpression({
Expand All @@ -40,10 +45,18 @@ export function createInitializationOnlyPreprocessor({

isInitializationPhase = false;

const {cleanValue} = extractAffixes(elementState.value, {prefix, postfix});

return {
elementState: maskitoTransform(elementState, {
mask: cleanNumberMask,
}),
elementState: maskitoTransform(
{
...elementState,
value: cleanValue,
},
{
mask: cleanNumberMask,
},
),
data,
};
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {MaskitoPostprocessor} from '@maskito/core';

import {escapeRegExp} from '../../../utils';
import {escapeRegExp, extractAffixes} from '../../../utils';

/**
* It removes repeated leading zeroes for integer part.
Expand All @@ -9,10 +9,17 @@ import {escapeRegExp} from '../../../utils';
* @example User types "000000" => 0|
* @example 0| => User types "5" => 5|
*/
export function createLeadingZeroesValidationPostprocessor(
decimalSeparator: string,
thousandSeparator: string,
): MaskitoPostprocessor {
export function createLeadingZeroesValidationPostprocessor({
decimalSeparator,
thousandSeparator,
prefix,
postfix,
}: {
decimalSeparator: string;
thousandSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPostprocessor {
const trimLeadingZeroes = (value: string): string => {
const escapedThousandSeparator = escapeRegExp(thousandSeparator);

Expand Down Expand Up @@ -42,8 +49,13 @@ export function createLeadingZeroesValidationPostprocessor(

return ({value, selection}) => {
const [from, to] = selection;
const hasDecimalSeparator = value.includes(decimalSeparator);
const [integerPart, decimalPart = ''] = value.split(decimalSeparator);
const {cleanValue, extractedPrefix, extractedPostfix} = extractAffixes(value, {
prefix,
postfix,
});

const hasDecimalSeparator = cleanValue.includes(decimalSeparator);
const [integerPart, decimalPart = ''] = cleanValue.split(decimalSeparator);
const zeroTrimmedIntegerPart = trimLeadingZeroes(integerPart);

if (integerPart === zeroTrimmedIntegerPart) {
Expand All @@ -55,9 +67,11 @@ export function createLeadingZeroesValidationPostprocessor(

return {
value:
extractedPrefix +
zeroTrimmedIntegerPart +
(hasDecimalSeparator ? decimalSeparator : '') +
decimalPart,
decimalPart +
extractedPostfix,
selection: [Math.max(newFrom, 0), Math.max(newTo, 0)],
};
};
Expand Down
Loading