Skip to content

Commit

Permalink
fix(kit): Number has problems with run-time updates of postfix (#380)
Browse files Browse the repository at this point in the history
  • Loading branch information
nsbarsukov authored Jul 24, 2023
1 parent d904842 commit 8210896
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,4 +270,43 @@ describe('Number | Prefix & Postfix', () => {
);
});
});

describe('runtime changes of postfix', () => {
beforeEach(() => {
cy.visit(DemoPath.Cypress);
cy.get('#runtime-postfix-changes input')
.focus()
.should('have.value', '1 year')
.as('input');
});

it('1| year => Type 0 => 10| years', () => {
cy.get('@input')
.type('{moveToStart}{rightArrow}')
.type('0')
.should('have.value', '10 years')
.should('have.prop', 'selectionStart', '10'.length)
.should('have.prop', 'selectionEnd', '10'.length);
});

it('10| years => Backspace => 1| year', () => {
cy.get('@input')
.type('{moveToStart}{rightArrow}')
.type('0')
.should('have.value', '10 years')
.type('{backspace}')
.should('have.value', '1 year')
.should('have.prop', 'selectionStart', '1'.length)
.should('have.prop', 'selectionEnd', '1'.length);
});

it('select all + delete', () => {
cy.get('@input')
.should('have.value', '1 year')
.type('{selectAll}{del}')
.should('have.value', '')
.should('have.prop', 'selectionStart', 0)
.should('have.prop', 'selectionEnd', 0);
});
});
});
3 changes: 3 additions & 0 deletions projects/demo/src/pages/cypress/cypress.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {CypressDocPageComponent} from './cypress.component';
import {TestDocExample1} from './examples/1-predicate/component';
import {TestDocExample2} from './examples/2-native-max-length/component';
import {TestDocExample3} from './examples/3-mirrored-prefix-postfix/component';
import {TestDocExample4, TestPipe4} from './examples/4-runtime-postfix-changes/component';

@NgModule({
imports: [
Expand All @@ -27,6 +28,8 @@ import {TestDocExample3} from './examples/3-mirrored-prefix-postfix/component';
TestDocExample1,
TestDocExample2,
TestDocExample3,
TestDocExample4,
TestPipe4,
],
exports: [CypressDocPageComponent],
})
Expand Down
4 changes: 4 additions & 0 deletions projects/demo/src/pages/cypress/cypress.template.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
<test-doc-example-3
id="mirrored-prefix-postfix"
></test-doc-example-3>

<test-doc-example-4
id="runtime-postfix-changes"
></test-doc-example-4>
</div>
</ng-template>
</tui-doc-page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
ChangeDetectionStrategy,
Component,
ElementRef,
Pipe,
PipeTransform,
ViewChild,
} from '@angular/core';
import {MaskitoOptions} from '@maskito/core';
import {maskitoNumberOptionsGenerator, maskitoParseNumber} from '@maskito/kit';

@Pipe({
name: 'calculateMask',
})
export class TestPipe4 implements PipeTransform {
transform(postfix: string): MaskitoOptions {
return maskitoNumberOptionsGenerator({
postfix,
precision: 2,
thousandSeparator: ' ',
});
}
}

@Component({
selector: 'test-doc-example-4',
template: `
<input
#inputRef
placeholder="Enter number"
value="1 year"
[maskito]="parsedValue | i18nPlural : pluralize | calculateMask"
/>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TestDocExample4 {
@ViewChild('inputRef', {read: ElementRef, static: true})
readonly inputRef!: ElementRef<HTMLInputElement>;

get parsedValue(): number {
return maskitoParseNumber(this.inputRef.nativeElement.value);
}

readonly pluralize = {
one: ` year`,
few: ` years`,
many: ` years`,
other: ` years`,
};
}
6 changes: 6 additions & 0 deletions projects/kit/src/lib/masks/number/number-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from './plugins';
import {
createDecimalZeroPaddingPostprocessor,
createInitializationOnlyPreprocessor,
createMinMaxPostprocessor,
createNonRemovableCharsDeletionPreprocessor,
createNotEmptyIntegerPartPreprocessor,
Expand Down Expand Up @@ -67,6 +68,11 @@ export function maskitoNumberOptionsGenerator({
isNegativeAllowed: min < 0,
}),
preprocessors: [
createInitializationOnlyPreprocessor({
decimalSeparator,
decimalPseudoSeparators,
pseudoMinuses,
}),
createPseudoCharactersPreprocessor(CHAR_MINUS, pseudoMinuses),
createPseudoCharactersPreprocessor(decimalSeparator, decimalPseudoSeparators),
createNotEmptyIntegerPartPreprocessor({decimalSeparator, precision}),
Expand Down
1 change: 1 addition & 0 deletions projects/kit/src/lib/masks/number/processors/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './decimal-zero-padding-postprocessor';
export * from './initialization-only-preprocessor';
export * from './leading-zeroes-validation-postprocessor';
export * from './min-max-postprocessor';
export * from './non-removable-chars-deletion-preprocessor';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {MaskitoPreprocessor, maskitoTransform} from '@maskito/core';

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

/**
* This preprocessor works only once at initialization phase (when `new Maskito(...)` is executed).
* This preprocessor helps to avoid conflicts during transition from one mask to another (for the same input).
* For example, the developer changes postfix (or other mask's props) during run-time.
* ```
* let maskitoOptions = maskitoNumberOptionsGenerator({postfix: ' year'});
* // [3 seconds later]
* maskitoOptions = maskitoNumberOptionsGenerator({postfix: ' years'});
* ```
*/
export function createInitializationOnlyPreprocessor({
decimalSeparator,
decimalPseudoSeparators,
pseudoMinuses,
}: {
decimalSeparator: string;
decimalPseudoSeparators: readonly string[];
pseudoMinuses: readonly string[];
}): MaskitoPreprocessor {
let isInitializationPhase = true;
const cleanNumberMask = generateMaskExpression({
decimalSeparator,
decimalPseudoSeparators,
pseudoMinuses,
prefix: '',
postfix: '',
thousandSeparator: '',
precision: Infinity,
isNegativeAllowed: true,
});

return ({elementState, data}) => {
if (!isInitializationPhase) {
return {elementState, data};
}

isInitializationPhase = false;

return {
elementState: maskitoTransform(elementState, {
mask: cleanNumberMask,
}),
data,
};
};
}
22 changes: 15 additions & 7 deletions projects/kit/src/lib/masks/number/tests/number-mask.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import {maskitoTransform} from '@maskito/core';
import {MASKITO_DEFAULT_OPTIONS, MaskitoOptions, maskitoTransform} from '@maskito/core';

import {maskitoNumberOptionsGenerator} from '../number-mask';

describe('Number', () => {
describe('`precision` is `0` and it is paste from clipboard', () => {
const options = maskitoNumberOptionsGenerator({
decimalSeparator: ',',
decimalPseudoSeparators: ['.'],
precision: 0,
describe('Number (maskitoTransform)', () => {
describe('`precision` is `0`', () => {
let options: MaskitoOptions = MASKITO_DEFAULT_OPTIONS;

beforeEach(() => {
options = maskitoNumberOptionsGenerator({
decimalSeparator: ',',
decimalPseudoSeparators: ['.'],
precision: 0,
});
});

it('drops decimal part (123,45)', () => {
Expand All @@ -17,5 +21,9 @@ describe('Number', () => {
it('drops decimal part (123.45)', () => {
expect(maskitoTransform('123.45', options)).toBe('123');
});

it('keeps minus sign (-123)', () => {
expect(maskitoTransform('-123', options)).toBe('−123');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,31 @@ export function generateMaskExpression({
thousandSeparator,
prefix,
postfix,
decimalPseudoSeparators = [],
pseudoMinuses = [],
}: {
decimalSeparator: string;
isNegativeAllowed: boolean;
precision: number;
thousandSeparator: string;
prefix: string;
postfix: string;
decimalPseudoSeparators?: readonly string[];
pseudoMinuses?: readonly string[];
}): MaskitoMask {
const computedPrefix = computeAllOptionalCharsRegExp(prefix);
const digit = '\\d';
const optionalMinus = isNegativeAllowed ? `${CHAR_MINUS}?` : '';
const optionalMinus = isNegativeAllowed
? `[${CHAR_MINUS}${pseudoMinuses.map(x => `\\${x}`).join('')}]?`
: '';
const integerPart = thousandSeparator
? `[${digit}${escapeRegExp(thousandSeparator)}]*`
: `[${digit}]*`;
const decimalPart =
precision > 0
? `(${escapeRegExp(decimalSeparator)}${digit}{0,${
Number.isFinite(precision) ? precision : ''
}})?`
? `([${escapeRegExp(decimalSeparator)}${decimalPseudoSeparators
.map(escapeRegExp)
.join('')}]${digit}{0,${Number.isFinite(precision) ? precision : ''}})?`
: '';
const computedPostfix = computeAllOptionalCharsRegExp(postfix);

Expand Down

0 comments on commit 8210896

Please sign in to comment.