Skip to content

Commit

Permalink
feat(kit): InputNumber uses Maskito instead of legacy text-mask
Browse files Browse the repository at this point in the history
  • Loading branch information
nsbarsukov committed Jun 26, 2023
1 parent dba09bc commit 22c1ba9
Show file tree
Hide file tree
Showing 19 changed files with 540 additions and 351 deletions.
2 changes: 2 additions & 0 deletions projects/core/utils/mask/create-auto-corrected-money-pipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {TuiTextMaskPipeHandler} from '@taiga-ui/core/mask';
import {TuiDecimalSymbol} from '@taiga-ui/core/types';

/**
* TODO: delete in v4.0
* @deprecated Use {@link https://tinkoff.github.io/maskito/kit/number Number} from {@link https://github.com/Tinkoff/maskito Maskito} instead <br/>
* Used to finish a number with zeros to a given precision
*/
export function tuiCreateAutoCorrectedNumberPipe(
Expand Down
2 changes: 2 additions & 0 deletions projects/core/utils/mask/create-number-mask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {tuiOtherDecimalSymbol} from '@taiga-ui/core/utils/format';
const NON_ZERO_DIGIT = /[1-9]/;

/**
* TODO: delete in v4.0
* @deprecated Use {@link https://tinkoff.github.io/maskito/kit/number Number} from {@link https://github.com/Tinkoff/maskito Maskito} instead <br/>
* Adaptation for {@link https://github.com/text-mask/text-mask/tree/master/addons#createnumbermask `createNumberMask`}
*/
export function tuiCreateNumberMask({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {TUI_DECIMAL_SYMBOLS} from '@taiga-ui/core/constants';
import {TuiNumberFormatSettings} from '@taiga-ui/core/interfaces';

/**
* TODO: delete in v4.0
* @deprecated Use {@link https://tinkoff.github.io/maskito/kit/number Number} from {@link https://github.com/Tinkoff/maskito Maskito} instead
*/
export function tuiEnableAutoCorrectDecimalSymbol({
thousandSeparator,
}: TuiNumberFormatSettings): boolean {
Expand Down
7 changes: 7 additions & 0 deletions projects/core/utils/mask/masked-money-value-is-empty.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import {CHAR_HYPHEN} from '@taiga-ui/cdk';

/**
* TODO: delete in v4.0
* @deprecated use {@link https://tinkoff.github.io/maskito/kit/number maskitoParseNumber} instead
* ```ts
* Number.isNaN(maskitoParseNumber(value, decimalSeparator))
* ```
*/
export function tuiMaskedMoneyValueIsEmpty(value: string): boolean {
switch (value) {
case ``:
Expand Down
4 changes: 4 additions & 0 deletions projects/core/utils/mask/masked-number-string-to-number.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {TuiDecimalSymbol} from '@taiga-ui/core/types';

/**
* TODO: delete in v4.0
* @deprecated use {@link https://tinkoff.github.io/maskito/kit/number maskitoParseNumber} instead
*/
export function tuiMaskedNumberStringToNumber(
value: string,
decimalsSymbol: TuiDecimalSymbol,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe(`TablePagination`, () => {
});

it(`With very long option name`, () => {
const longNumber = 10000000000000000000;
const longNumber = Number.MAX_SAFE_INTEGER;

cy.tuiVisit(
`/components/table-pagination/API?items=[0, ${longNumber}]&size=${longNumber}&total=${longNumber}&page=0`,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
/* eslint-disable no-irregular-whitespace */
/* eslint-disable @taiga-ui/no-deep-imports */
import {
CHAR_EM_DASH,
CHAR_EN_DASH,
CHAR_HYPHEN,
CHAR_MINUS,
} from '@taiga-ui/cdk/constants';

describe(`InputNumber`, () => {
describe(`API`, () => {
it(`Infinite precision`, () => {
Expand Down Expand Up @@ -85,4 +94,263 @@ describe(`InputNumber`, () => {
}
});
});

describe(`Caret navigation`, () => {
beforeEach(() => {
cy.viewport(`iphone-x`);
});

describe(`if user tries to erase padded decimal zeroes (decimal="always"), mask triggers caret navigation`, () => {
beforeEach(() => {
cy.tuiVisit(`components/input-number/API?decimal=always&precision=2`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`105,00| => Backspace => 105,0|0`, () => {
cy.get(`@input`)
.type(`105,00`)
.type(`{backspace}`)
.should(`have.value`, `105,00`)
.should(`have.prop`, `selectionStart`, `105,0`.length)
.should(`have.prop`, `selectionEnd`, `105,0`.length);
});

it(`105,0|0 => Backspace => 105,|00`, () => {
cy.get(`@input`)
.type(`105,00`)
.type(`{leftArrow}{backspace}`)
.should(`have.value`, `105,00`)
.should(`have.prop`, `selectionStart`, `105,`.length)
.should(`have.prop`, `selectionEnd`, `105,`.length);
});

it(`105,|00 => Backspace => 105|,00`, () => {
cy.get(`@input`)
.type(`105,00`)
.type(`{leftArrow}`.repeat(2))
.type(`{backspace}`)
.should(`have.value`, `105,00`)
.should(`have.prop`, `selectionStart`, `105`.length)
.should(`have.prop`, `selectionEnd`, `105`.length);
});

it(`105,|00 => Delete => 105,0|0`, () => {
cy.get(`@input`)
.type(`105,00`)
.type(`{leftArrow}`.repeat(2))
.type(`{del}`)
.should(`have.value`, `105,00`)
.should(`have.prop`, `selectionStart`, `105,0`.length)
.should(`have.prop`, `selectionEnd`, `105,0`.length);
});
});

describe(`if user tries to erase thousand separator, mask triggers caret navigation`, () => {
beforeEach(() => {
cy.tuiVisit(`components/input-number/API?decimal=not-zero`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`1| 000 => Delete => 1 |000`, () => {
cy.get(`@input`)
.type(`1000`)
.type(`{moveToStart}{rightArrow}`)
.type(`{del}`)
.should(`have.value`, `1 000`)
.should(`have.prop`, `selectionStart`, `1 `.length)
.should(`have.prop`, `selectionEnd`, `1 `.length);
});

it(`1 |000 => Backspace => 1| 000`, () => {
cy.get(`@input`)
.type(`1000`)
.type(`{moveToStart}{rightArrow}{rightArrow}`)
.should(`have.prop`, `selectionStart`, `1 `.length)
.should(`have.prop`, `selectionEnd`, `1 `.length)
.type(`{backspace}`)
.should(`have.value`, `1 000`)
.should(`have.prop`, `selectionStart`, `1`.length)
.should(`have.prop`, `selectionEnd`, `1`.length);
});
});
});

describe(`[min] prop`, () => {
describe(`[min] property is positive number`, () => {
beforeEach(() => {
cy.viewport(`iphone-x`);
cy.tuiVisit(`components/input-number/API?min=5`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`rejects minus sign`, () => {
cy.get(`@input`)
.type(`${CHAR_MINUS}${CHAR_HYPHEN}${CHAR_EN_DASH}${CHAR_EM_DASH}9`)
.should(`have.value`, `9`)
.should(`have.prop`, `selectionStart`, 1)
.should(`have.prop`, `selectionEnd`, 1);
});

it(`validates positive value only on blur`, () => {
cy.get(`@input`)
.type(`2`) // less than [min]
.wait(100) // to be sure that value is not changed even in case of some async validation
.should(`have.value`, `2`)
.should(`have.prop`, `selectionStart`, 1)
.should(`have.prop`, `selectionEnd`, 1)
.blur()
.should(`have.value`, `5`);
});
});

describe(`[min] property is negative number`, () => {
beforeEach(() => {
cy.viewport(`iphone-x`);
cy.tuiVisit(`components/input-number/API?min=-5`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`immediately validates negative value`, () => {
cy.get(`@input`)
.type(`-10`) // less than [min]
.should(`have.value`, `${CHAR_MINUS}5`)
.should(`have.prop`, `selectionStart`, 2)
.should(`have.prop`, `selectionEnd`, 2);
});

it(`don't touch any positive value`, () => {
cy.get(`@input`)
.type(`1`)
.should(`have.value`, `1`)
.type(`0`)
.should(`have.value`, `10`)
.blur()
.wait(100) // to be sure that value is not changed even in case of some async validation
.should(`have.value`, `10`);
});
});
});

describe(`[max] prop`, () => {
describe(`[max] property is negative number`, () => {
beforeEach(() => {
cy.viewport(`iphone-x`);
cy.tuiVisit(`components/input-number/API?max=-5`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`validates negative value only on blur`, () => {
cy.get(`@input`)
.type(`-1`) // more than [max]
.wait(100) // to be sure that value is not changed even in case of some async validation
.should(`have.value`, `${CHAR_MINUS}1`)
.should(`have.prop`, `selectionStart`, 2)
.should(`have.prop`, `selectionEnd`, 2)
.blur()
.should(`have.value`, `${CHAR_MINUS}5`);
});
});

describe(`[max] property is positive number`, () => {
beforeEach(() => {
cy.viewport(`iphone-x`);
cy.tuiVisit(`components/input-number/API?max=12`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`).clear();
});

it(`immediately validates positive value`, () => {
cy.get(`@input`)
.type(`19`) // more than [max]
.should(`have.value`, `12`)
.should(`have.prop`, `selectionStart`, 2)
.should(`have.prop`, `selectionEnd`, 2);
});

it(`don't touch any negative value`, () => {
cy.get(`@input`)
.type(`-1`)
.should(`have.value`, `${CHAR_MINUS}1`)
.type(`9`)
.should(`have.value`, `${CHAR_MINUS}19`)
.blur()
.wait(100) // to be sure that value is not changed even in case of some async validation
.should(`have.value`, `${CHAR_MINUS}19`);
});
});
});

describe(`value formatting on blur`, () => {
it(`Value 42 (decimal=not-zero) => 42`, () => {
cy.tuiVisit(`components/input-number/API?precision=2&decimal=not-zero`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`)
.type(`{selectall}`)
.type(`42`)
.blur()
.should(`have.value`, `42`);
});

it(`Value 42,1 (decimal=not-zero) => 42,10`, () => {
cy.tuiVisit(`components/input-number/API?precision=2&decimal=not-zero`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`)
.type(`{selectall}`)
.type(`42,1`)
.blur()
.should(`have.value`, `42,10`);
});

it(`Value 42,00 (decimal=not-zero) => 42`, () => {
cy.tuiVisit(`components/input-number/API?precision=2&decimal=not-zero`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`)
.type(`{selectall}`)
.type(`42,00`)
.blur()
.should(`have.value`, `42`);
});

it(`Value 42 (decimal=never) => 42`, () => {
cy.tuiVisit(`components/input-number/API?precision=2&decimal=never`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`)
.type(`{selectall}`)
.type(`42`)
.blur()
.should(`have.value`, `42`);
});

it(`Value 42 (decimal=always) => 42`, () => {
cy.tuiVisit(`components/input-number/API?precision=2&decimal=always`);
initializeAliases(`#demo-content tui-input-number`);

cy.get(`@input`)
.type(`{selectall}`)
.type(`42`)
.blur()
.should(`have.value`, `42,00`);
});
});

function initializeAliases(selector: string): void {
cy.get(selector)
.findByAutomationId(`tui-primitive-textfield__native-input`)
.as(`input`);
}
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// eslint-disable-next-line @taiga-ui/no-deep-imports
import {CHAR_MINUS} from '@taiga-ui/cdk/constants';

describe(`InputRange`, () => {
beforeEach(() => {
cy.viewport(`macbook-13`);
Expand All @@ -15,12 +18,12 @@ describe(`InputRange`, () => {
cy.get(`body`).type(`{downarrow}`);

cy.get(`@leftSlider`).should(`have.value`, -5);
cy.get(`@leftTextInput`).should(`have.value`, -5);
cy.get(`@leftTextInput`).should(`have.value`, `${CHAR_MINUS}5`);

cy.get(`body`).type(`{downarrow}`);

cy.get(`@leftSlider`).should(`have.value`, -10);
cy.get(`@leftTextInput`).should(`have.value`, -10);
cy.get(`@leftTextInput`).should(`have.value`, `${CHAR_MINUS}10`);
});

it(`pressing Arrow Down decreases RIGHT value when RIGHT text input is focused`, () => {
Expand Down Expand Up @@ -174,7 +177,9 @@ describe(`InputRange`, () => {
cy.get(`@rightSlider`).should(`have.value`, 10);
cy.get(`@rightTextInput`).should(`have.value`, 10);

cy.get(`@leftTextInput`).should(`have.value`, -100).should(`be.focused`);
cy.get(`@leftTextInput`)
.should(`have.value`, `${CHAR_MINUS}100`)
.should(`be.focused`);
});
});

Expand Down Expand Up @@ -260,7 +265,9 @@ describe(`InputRange`, () => {
.click(`left`, {force: true})
.should(`have.value`, -20);

cy.get(`@leftTextInput`).should(`have.value`, -20).should(`be.focused`);
cy.get(`@leftTextInput`)
.should(`have.value`, `${CHAR_MINUS}20`)
.should(`be.focused`);
});

it(`does not focus anything if no text input was focused before`, () => {
Expand All @@ -272,7 +279,7 @@ describe(`InputRange`, () => {
.should(`have.value`, -20);

cy.get(`@leftTextInput`)
.should(`have.value`, -20)
.should(`have.value`, `${CHAR_MINUS}20`)
.should(`not.be.focused`);
cy.get(`@rightTextInput`)
.should(`have.value`, 10)
Expand All @@ -283,7 +290,7 @@ describe(`InputRange`, () => {
.should(`have.value`, 20);

cy.get(`@leftTextInput`)
.should(`have.value`, -20)
.should(`have.value`, `${CHAR_MINUS}20`)
.should(`not.be.focused`);
cy.get(`@rightTextInput`)
.should(`have.value`, 20)
Expand Down
Loading

0 comments on commit 22c1ba9

Please sign in to comment.