Skip to content

Commit

Permalink
feat(kit): fixed prefix and postfix with dot processing
Browse files Browse the repository at this point in the history
  • Loading branch information
aktanoff committed Dec 23, 2023
1 parent 9a36771 commit 8c54ea6
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 61 deletions.
41 changes: 31 additions & 10 deletions projects/kit/src/lib/masks/number/number-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,33 @@ export function maskitoNumberOptionsGenerator({
decimalPseudoSeparators: validatedDecimalPseudoSeparators,
pseudoMinuses,
}),
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),
createRepeatedDecimalSeparatorPreprocessor({
decimalSeparator,
prefix,
postfix,
}),
],
postprocessors: [
createMinMaxPostprocessor({decimalSeparator, min, max}),
createMinMaxPostprocessor({decimalSeparator, min, max, prefix, postfix}),
maskitoPrefixPostprocessorGenerator(prefix),
maskitoPostfixPostprocessorGenerator(postfix),
createThousandSeparatorPostprocessor({
Expand All @@ -103,13 +114,23 @@ export function maskitoNumberOptionsGenerator({
decimalSeparator,
decimalZeroPadding,
precision,
prefix,
postfix,
}),
],
plugins: [
createLeadingZeroesValidationPlugin(decimalSeparator, thousandSeparator),
createNotEmptyIntegerPlugin(decimalSeparator),
createMinMaxPlugin({min, max, decimalSeparator}),
createLeadingZeroesValidationPlugin({
decimalSeparator,
thousandSeparator,
prefix,
postfix,
}),
createNotEmptyIntegerPlugin({
decimalSeparator,
prefix,
postfix,
}),
createMinMaxPlugin({min, max, decimalSeparator, prefix, postfix}),
],
overwriteMode: decimalZeroPadding
? ({value, selection: [from]}) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {MaskitoPlugin, maskitoUpdateElement} from '@maskito/core';

import {maskitoEventHandler} from '../../../plugins';
import {createLeadingZeroesValidationPostprocessor} from '../processors';
import {extractPrefixAndPostfix} from '../utils/extract-prefix-and-postfix';

const DUMMY_SELECTION = [0, 0] as const;

Expand All @@ -10,10 +11,17 @@ const DUMMY_SELECTION = [0, 0] as const;
* @example 000000 => blur => 0
* @example 00005 => blur => 5
*/
export function createLeadingZeroesValidationPlugin(
decimalSeparator: string,
thousandSeparator: string,
): MaskitoPlugin {
export function createLeadingZeroesValidationPlugin({
decimalSeparator,
thousandSeparator,
prefix,
postfix,
}: {
decimalSeparator: string;
thousandSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPlugin {
const dropRepeatedLeadingZeroes = createLeadingZeroesValidationPostprocessor(
decimalSeparator,
thousandSeparator,
Expand All @@ -22,13 +30,23 @@ export function createLeadingZeroesValidationPlugin(
return maskitoEventHandler(
'blur',
element => {
const newValue = dropRepeatedLeadingZeroes(
{
const {cleanValue, extractedPostfix, extractedPrefix} =
extractPrefixAndPostfix({
value: element.value,
selection: DUMMY_SELECTION,
},
{value: '', selection: DUMMY_SELECTION},
).value;
prefix,
postfix,
});

const newValue =
extractedPrefix +
dropRepeatedLeadingZeroes(
{
value: cleanValue,
selection: DUMMY_SELECTION,
},
{value: '', selection: DUMMY_SELECTION},
).value +
extractedPostfix;

if (element.value !== newValue) {
maskitoUpdateElement(element, newValue);
Expand Down
11 changes: 10 additions & 1 deletion projects/kit/src/lib/masks/number/plugins/min-max.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,24 @@ export function createMinMaxPlugin({
min,
max,
decimalSeparator,
prefix,
postfix,
}: {
min: number;
max: number;
decimalSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPlugin {
return maskitoEventHandler(
'blur',
(element, options) => {
const parsedNumber = maskitoParseNumber(element.value, decimalSeparator);
const parsedNumber = maskitoParseNumber(
element.value,
decimalSeparator,
prefix,
postfix,
);
const clampedNumber = clamp(parsedNumber, min, max);

if (!Number.isNaN(parsedNumber) && parsedNumber !== clampedNumber) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,38 @@ import {MaskitoPlugin, maskitoUpdateElement} from '@maskito/core';

import {maskitoEventHandler} from '../../../plugins';
import {escapeRegExp} from '../../../utils';
import {extractPrefixAndPostfix} from '../utils/extract-prefix-and-postfix';

/**
* 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} =
extractPrefixAndPostfix({
value: 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
@@ -1,7 +1,8 @@
import {MaskitoPostprocessor} from '@maskito/core';

import {escapeRegExp, identity} from '../../../utils';
import {identity} from '../../../utils';
import {maskitoParseNumber} from '../utils';
import {extractPrefixAndPostfix} from '../utils/extract-prefix-and-postfix';

/**
* If `decimalZeroPadding` is `true`, it pads decimal part with zeroes
Expand All @@ -12,34 +13,43 @@ 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} = extractPrefixAndPostfix({
value,
prefix,
postfix,
});

if (
Number.isNaN(
maskitoParseNumber(cleanValue, decimalSeparator, prefix, postfix),
)
) {
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
Expand Up @@ -11,13 +11,17 @@ export function createMinMaxPostprocessor({
min,
max,
decimalSeparator,
prefix,
postfix,
}: {
min: number;
max: number;
decimalSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPostprocessor {
return ({value, selection}) => {
const parsedNumber = maskitoParseNumber(value, decimalSeparator);
const parsedNumber = maskitoParseNumber(value, decimalSeparator, prefix, postfix);
const limitedValue =
/**
* We cannot limit lower bound if user enters positive number.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
import {MaskitoPreprocessor} from '@maskito/core';

import {extractPrefixAndPostfix} from '../utils/extract-prefix-and-postfix';

/**
* It replaces pseudo characters with valid one.
* @example User types '.' (but separator is equal to comma) => dot is replaced with comma.
* @example User types hyphen / en-dash / em-dash => it is replaced with minus.
*/
export function createPseudoCharactersPreprocessor(
validCharacter: string,
pseudoCharacters: string[],
): MaskitoPreprocessor {
export function createPseudoCharactersPreprocessor({
validCharacter,
pseudoCharacters,
prefix,
postfix,
}: {
validCharacter: string;
pseudoCharacters: string[];
prefix: string;
postfix: string;
}): MaskitoPreprocessor {
const pseudoCharactersRegExp = new RegExp(`[${pseudoCharacters.join('')}]`, 'gi');

return ({elementState, data}) => {
const {value, selection} = elementState;

const {cleanValue, extractedPostfix, extractedPrefix} = extractPrefixAndPostfix({
value,
prefix,
postfix,
});

const newValue =
extractedPrefix +
cleanValue.replace(pseudoCharactersRegExp, validCharacter) +
extractedPostfix;

return {
elementState: {
selection,
value: value.replace(pseudoCharactersRegExp, validCharacter),
value: newValue,
},
data: data.replace(pseudoCharactersRegExp, validCharacter),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import {MaskitoPreprocessor} from '@maskito/core';

import {escapeRegExp} from '../../../utils';
import {extractPrefixAndPostfix} from '../utils/extract-prefix-and-postfix';

/**
* It rejects new typed decimal separator if it already exists in text field.
* Behaviour is similar to native <input type="number"> (Chrome).
* @example 1|23,45 => Press comma (decimal separator) => 1|23,45 (do nothing).
*/
export function createRepeatedDecimalSeparatorPreprocessor(
decimalSeparator: string,
): MaskitoPreprocessor {
export function createRepeatedDecimalSeparatorPreprocessor({
decimalSeparator,
prefix,
postfix,
}: {
decimalSeparator: string;
prefix: string;
postfix: string;
}): MaskitoPreprocessor {
return ({elementState, data}) => {
const {value, selection} = elementState;
const [from, to] = selection;

const {cleanValue} = extractPrefixAndPostfix({value, prefix, postfix});

return {
elementState,
data:
!value.includes(decimalSeparator) ||
!cleanValue.includes(decimalSeparator) ||
value.slice(from, to + 1).includes(decimalSeparator)
? data
: data.replace(new RegExp(escapeRegExp(decimalSeparator), 'gi'), ''),
Expand Down
Loading

0 comments on commit 8c54ea6

Please sign in to comment.