diff --git a/projects/addon-commerce/pipes/amount/amount.pipe.ts b/projects/addon-commerce/pipes/amount/amount.pipe.ts index 529d1e7a16ae..d42389aec28b 100644 --- a/projects/addon-commerce/pipes/amount/amount.pipe.ts +++ b/projects/addon-commerce/pipes/amount/amount.pipe.ts @@ -3,14 +3,14 @@ import {inject, Pipe} from '@angular/core'; import type {TuiCurrencyVariants} from '@taiga-ui/addon-commerce/types'; import {tuiFormatCurrency, tuiFormatSignSymbol} from '@taiga-ui/addon-commerce/utils'; import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiHorizontalDirection} from '@taiga-ui/core'; +import type {TuiHorizontalDirection} from '@taiga-ui/core'; import {TUI_NUMBER_FORMAT, tuiFormatNumber} from '@taiga-ui/core'; import type {Observable} from 'rxjs'; import {map} from 'rxjs'; import {TUI_AMOUNT_OPTIONS} from './amount.options'; -const DEFAULT_DECIMAL_LIMIT = 2; +const DEFAULT_PRECISION = 2; @Pipe({ name: 'tuiAmount', @@ -31,13 +31,9 @@ export class TuiAmountPipe implements PipeTransform { const currencySymbol = tuiFormatCurrency(currency); const formatted = tuiFormatNumber(Math.abs(value), { ...format, - decimalLimit: this.getDecimalLimit( - value, - Number.isNaN(format.decimalLimit) - ? DEFAULT_DECIMAL_LIMIT - : format.decimalLimit, - format?.decimal || 'not-zero', - ), + precision: Number.isNaN(format.precision) + ? DEFAULT_PRECISION + : format.precision, }); const space = currencySymbol?.length > 1 || currencyAlign === 'right' @@ -50,8 +46,4 @@ export class TuiAmountPipe implements PipeTransform { }), ); } - - private getDecimalLimit(value: number, limit: number, decimal: TuiDecimal): number { - return decimal === 'always' || (decimal === 'not-zero' && value % 1) ? limit : 0; - } } diff --git a/projects/core/constants/default-number-format.ts b/projects/core/constants/default-number-format.ts index c4ceb97ee183..4d0a51cd875c 100644 --- a/projects/core/constants/default-number-format.ts +++ b/projects/core/constants/default-number-format.ts @@ -2,10 +2,9 @@ import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk'; import type {TuiNumberFormatSettings} from '@taiga-ui/core/interfaces'; export const TUI_DEFAULT_NUMBER_FORMAT: TuiNumberFormatSettings = { - decimalLimit: NaN, + precision: NaN, decimalSeparator: ',', thousandSeparator: CHAR_NO_BREAK_SPACE, - zeroPadding: true, rounding: 'truncate', - decimal: 'not-zero', + decimalMode: 'pad', }; diff --git a/projects/core/interfaces/number-format-settings.ts b/projects/core/interfaces/number-format-settings.ts index d01e0585cb2c..8ee06c5959c6 100644 --- a/projects/core/interfaces/number-format-settings.ts +++ b/projects/core/interfaces/number-format-settings.ts @@ -1,5 +1,5 @@ import type {TuiRounding} from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiDecimalSymbol} from '@taiga-ui/core/types'; +import type {TuiDecimalMode, TuiDecimalSymbol} from '@taiga-ui/core/types'; /** * Formatting configuration for displayed numbers @@ -9,7 +9,7 @@ export interface TuiNumberFormatSettings { * Number of digits of decimal part. * @note Use `Infinity` to keep untouched. */ - readonly decimalLimit: number; + readonly precision: number; /** * Separator between the integer and the decimal part. * @example 0,42 (',' by default) @@ -24,12 +24,8 @@ export interface TuiNumberFormatSettings { * @example 360 000 (' ' by default) */ readonly thousandSeparator: string; - /** - * Enable zeros at the end of decimal part. - */ - readonly zeroPadding: boolean; /** * Decimal part display mode. ('not-zero' by default) */ - readonly decimal: TuiDecimal; + readonly decimalMode: TuiDecimalMode; } diff --git a/projects/core/pipes/format-number/format-number.pipe.ts b/projects/core/pipes/format-number/format-number.pipe.ts index f3b63349d792..e903c7c96fa3 100644 --- a/projects/core/pipes/format-number/format-number.pipe.ts +++ b/projects/core/pipes/format-number/format-number.pipe.ts @@ -24,9 +24,9 @@ export class TuiFormatNumberPipe implements PipeTransform { map(format => tuiFormatNumber(value, { ...format, - decimalLimit: Number.isNaN(format.decimalLimit) + precision: Number.isNaN(format.precision) ? Infinity - : format.decimalLimit, + : format.precision, ...settings, }), ), diff --git a/projects/core/types/decimal-mode.ts b/projects/core/types/decimal-mode.ts new file mode 100644 index 000000000000..c8902c2689be --- /dev/null +++ b/projects/core/types/decimal-mode.ts @@ -0,0 +1 @@ +export type TuiDecimalMode = 'always' | 'not-zero' | 'pad'; diff --git a/projects/core/types/decimal.ts b/projects/core/types/decimal.ts deleted file mode 100644 index 812bb24f71f0..000000000000 --- a/projects/core/types/decimal.ts +++ /dev/null @@ -1 +0,0 @@ -export type TuiDecimal = 'always' | 'never' | 'not-zero'; diff --git a/projects/core/types/index.ts b/projects/core/types/index.ts index 63e50582a4b5..76c7f534197e 100644 --- a/projects/core/types/index.ts +++ b/projects/core/types/index.ts @@ -1,7 +1,7 @@ export * from './brightness'; export * from './calendar-view'; export * from './data-list-role'; -export * from './decimal'; +export * from './decimal-mode'; export * from './decimal-symbol'; export * from './direction'; export * from './dropdown-align'; diff --git a/projects/core/utils/format/format-number.ts b/projects/core/utils/format/format-number.ts index ea6972306cd7..3c4ae264289c 100644 --- a/projects/core/utils/format/format-number.ts +++ b/projects/core/utils/format/format-number.ts @@ -16,23 +16,25 @@ export function tuiFormatNumber( value: number, settings: Partial = {}, ): string { - const {decimalLimit, decimalSeparator, thousandSeparator, zeroPadding, rounding} = { + const {precision, decimalSeparator, thousandSeparator, decimalMode, rounding} = { ...TUI_DEFAULT_NUMBER_FORMAT, - decimalLimit: Infinity, + decimalMode: 'always', + precision: Infinity, ...settings, }; - const rounded = Number.isFinite(decimalLimit) - ? tuiRoundWith({value, precision: decimalLimit, method: rounding}) + const rounded = Number.isFinite(precision) + ? tuiRoundWith({value, precision, method: rounding}) : value; const integerPartString = String(Math.floor(Math.abs(rounded))); - let fractionPartPadded = tuiGetFractionPartPadded(rounded, decimalLimit); + let fractionPartPadded = tuiGetFractionPartPadded(rounded, precision); + const hasFraction = Number(fractionPartPadded) > 0; - if (Number.isFinite(decimalLimit)) { - if (zeroPadding) { + if (Number.isFinite(precision)) { + if (decimalMode === 'always' || (hasFraction && decimalMode === 'pad')) { const zeroPaddingSize: number = Math.max( - decimalLimit - fractionPartPadded.length, + precision - fractionPartPadded.length, 0, ); const zeroPartString = '0'.repeat(zeroPaddingSize); diff --git a/projects/core/utils/format/test/format-number.spec.ts b/projects/core/utils/format/test/format-number.spec.ts index 84db80e12ca2..a51603ce1723 100644 --- a/projects/core/utils/format/test/format-number.spec.ts +++ b/projects/core/utils/format/test/format-number.spec.ts @@ -34,19 +34,19 @@ describe('Number formatting', () => { }); it('finishes the fractional part with zeros to a given value', () => { - expect(tuiFormatNumber(123, {decimalLimit: 2})).toBe('123,00'); + expect(tuiFormatNumber(123, {precision: 2})).toBe('123,00'); }); it('discards the extra fractional part', () => { - expect(tuiFormatNumber(1.234, {decimalLimit: 2})).toBe('1,23'); + expect(tuiFormatNumber(1.234, {precision: 2})).toBe('1,23'); }); it('discards the fractional part altogether', () => { - expect(tuiFormatNumber(5.678, {decimalLimit: 0})).toBe('5'); + expect(tuiFormatNumber(5.678, {precision: 0})).toBe('5'); }); it('accepts custom fractional separator', () => { - expect(tuiFormatNumber(123.45, {decimalLimit: 2, decimalSeparator: '.'})).toBe( + expect(tuiFormatNumber(123.45, {precision: 2, decimalSeparator: '.'})).toBe( '123.45', ); }); @@ -54,7 +54,7 @@ describe('Number formatting', () => { it('accepts custom thousands separator', () => { expect( tuiFormatNumber(12345.67, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', }), @@ -64,10 +64,10 @@ describe('Number formatting', () => { it('do not add zeros when disable zero padding flag', () => { expect( tuiFormatNumber(12345.6, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', - zeroPadding: false, + decimalMode: 'not-zero', }), ).toBe('12.345,6'); }); @@ -75,7 +75,7 @@ describe('Number formatting', () => { it('add zeros with default behavior', () => { expect( tuiFormatNumber(12345.6, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', }), @@ -83,49 +83,60 @@ describe('Number formatting', () => { }); it('value with exponent and fractional part with and decimal bigger than precision', () => { - expect(tuiFormatNumber(1.23e-8, {decimalLimit: 12})).toBe('0,000000012300'); + expect(tuiFormatNumber(1.23e-8, {precision: 12})).toBe('0,000000012300'); }); - it('deletes trailing zeros when zero padding flag is disabled', () => { + it('deletes trailing zeros when decimal mode is not-zero', () => { expect( tuiFormatNumber(12345.6078, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', - zeroPadding: false, + decimalMode: 'not-zero', }), ).toBe('12.345,6'); }); - it('displays without decimal separator when zero padding flag is disabled and there is no significant digits', () => { + it('displays without decimal separator when decimal mode is pad and there is no significant digits', () => { expect( tuiFormatNumber(12345.006, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', - zeroPadding: false, + decimalMode: 'pad', }), ).toBe('12.345'); }); - it('does not delete significant zeros in decimal part when padding flag is disabled', () => { + it('does not delete significant zeros in decimal part when when decimal mode is "pad"', () => { expect( tuiFormatNumber(0.01, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', - zeroPadding: false, + decimalMode: 'pad', }), ).toBe('0,01'); }); - it('deletes trailing zeros only in decimal part when zero padding flag is disabled', () => { + it('deletes trailing zeros only in decimal part when decimal mode is "pad"', () => { expect( tuiFormatNumber(0.001, { - decimalLimit: 2, + precision: 2, decimalSeparator: ',', thousandSeparator: '.', - zeroPadding: false, + decimalMode: 'pad', + }), + ).toBe('0'); + }); + + it('deletes trailing zeros only in decimal part when decimal mode is "not-zero"', () => { + expect( + tuiFormatNumber(0.001, { + precision: 2, + decimalSeparator: ',', + thousandSeparator: '.', + decimalMode: 'not-zero', }), ).toBe('0'); }); diff --git a/projects/demo-playwright/tests/kit/input-number/input-number.spec.ts b/projects/demo-playwright/tests/kit/input-number/input-number.spec.ts index c95571347893..1a497c42594f 100644 --- a/projects/demo-playwright/tests/kit/input-number/input-number.spec.ts +++ b/projects/demo-playwright/tests/kit/input-number/input-number.spec.ts @@ -84,11 +84,11 @@ test.describe('InputNumber', () => { }); test.describe('Caret navigation', () => { - test.describe('if user tries to erase padded decimal zeroes (decimal="always"), mask triggers caret navigation', () => { + test.describe('if user tries to erase padded decimal zeroes (decimalMode="always"), mask triggers caret navigation', () => { test.beforeEach(async ({page}) => { await tuiGoto( page, - '/components/input-number/API?decimal=always&precision=2', + '/components/input-number/API?decimalMode=always&precision=2', ); example = new TuiDocumentationApiPagePO(page).apiPageExample; @@ -134,7 +134,7 @@ test.describe('InputNumber', () => { test.describe('if user tries to erase thousand separator, mask triggers caret navigation', () => { test.beforeEach(async ({page}) => { - await tuiGoto(page, '/components/input-number/API?decimal=not-zero'); + await tuiGoto(page, '/components/input-number/API?decimalMode=not-zero'); example = new TuiDocumentationApiPagePO(page).apiPageExample; input = example.getByTestId('tui-primitive-textfield__native-input'); @@ -319,58 +319,79 @@ test.describe('InputNumber', () => { input = example.getByTestId('tui-primitive-textfield__native-input'); }); - test('Value 42 (decimal=not-zero) => 42', async ({page}) => { + test('Value 42 (decimalMode=not-zero) => 42', async ({page}) => { await tuiGoto( page, - 'components/input-number/API?precision=2&decimal=not-zero', + 'components/input-number/API?precision=2&decimalMode=not-zero', ); await input.fill('42'); + await expect(input).toHaveValue('42'); await expect(input).toHaveJSProperty('selectionStart', 2); await expect(input).toHaveJSProperty('selectionEnd', 2); await expect(example).toHaveScreenshot('26-input-number.png'); }); - test('Value 42,1 (decimal=not-zero) => 42,10', async ({page}) => { + test('Value 42,1 (decimalMode=not-zero) => 42,1', async ({page}) => { await tuiGoto( page, - '/components/input-number/API?precision=2&decimal=not-zero', + '/components/input-number/API?precision=2&decimalMode=not-zero', ); await input.fill('42,1'); + await expect(input).toHaveValue('42,1'); await expect(input).toHaveJSProperty('selectionStart', 4); await expect(input).toHaveJSProperty('selectionEnd', 4); + await input.blur(); + await expect(input).toHaveValue('42,1'); await expect(example).toHaveScreenshot('27-input-number.png'); }); - test('Value 42,00 (decimal=not-zero) => 42', async ({page}) => { + test('Value 42,1 (decimalMode=pad) => 42,10', async ({page}) => { await tuiGoto( page, - '/components/input-number/API?precision=2&decimal=not-zero', + '/components/input-number/API?precision=2&decimalMode=pad', + ); + + await input.fill('42,1'); + await expect(input).toHaveValue('42,1'); + await expect(input).toHaveJSProperty('selectionStart', 4); + await expect(input).toHaveJSProperty('selectionEnd', 4); + await input.blur(); + await expect(input).toHaveValue('42,10'); + await expect(example).toHaveScreenshot('28-input-number.png'); + }); + + test('Value 42,00 (decimalMode=not-zero) => 42', async ({page}) => { + await tuiGoto( + page, + '/components/input-number/API?precision=2&decimalMode=not-zero', ); await input.fill('42,00'); await expect(input).toHaveJSProperty('selectionStart', 5); await expect(input).toHaveJSProperty('selectionEnd', 5); - await expect(example).toHaveScreenshot('28-input-number.png'); + await expect(example).toHaveScreenshot('29-input-number.png'); }); - test('Value 42 (decimal=never) => 42', async ({page}) => { - await tuiGoto(page, '/components/input-number/API?precision=2&decimal=never'); + test('Value 42,1 (precision=0) => 42', async ({page}) => { + await tuiGoto(page, '/components/input-number/API?precision=0'); - await input.fill('42'); - await expect(example).toHaveScreenshot('29-input-number.png'); + await input.fill('42,1'); + await expect(input).toHaveValue('42'); + await expect(example).toHaveScreenshot('30-input-number.png'); }); - test('Value 42 (decimal=always) => 42', async ({page}) => { + test('Value 42 (decimalMode=always) => 42.00', async ({page}) => { await tuiGoto( page, - '/components/input-number/API?precision=2&decimal=always', + '/components/input-number/API?precision=2&decimalMode=always', ); await input.fill('42'); + await expect(input).toHaveValue('42,00'); await expect(input).toHaveJSProperty('selectionStart', 2); await expect(input).toHaveJSProperty('selectionEnd', 2); - await expect(example).toHaveScreenshot('30-input-number.png'); + await expect(example).toHaveScreenshot('31-input-number.png'); }); test("text field does not contain any digit (only prefix + postfix) => clear text field's value on blur", async ({ @@ -385,7 +406,7 @@ test.describe('InputNumber', () => { await expect(input).toHaveValue('$ kg'); await expect(input).toHaveJSProperty('selectionStart', 1); await expect(input).toHaveJSProperty('selectionEnd', 1); - await expect(example).toHaveScreenshot('31-input-number.png'); + await expect(example).toHaveScreenshot('32-input-number.png'); }); }); }); diff --git a/projects/demo/src/modules/app/app.routes.ts b/projects/demo/src/modules/app/app.routes.ts index 6a7785511ef2..70f4996f8f49 100644 --- a/projects/demo/src/modules/app/app.routes.ts +++ b/projects/demo/src/modules/app/app.routes.ts @@ -1810,6 +1810,12 @@ export const ROUTES: Routes = [ title: 'TextfieldController', }, }, + route({ + path: 'directives/number-format', + title: 'NumberFormat', + loadComponent: async () => + import('../directives/number-format/number-format.component'), + }), // UTILS { diff --git a/projects/demo/src/modules/app/pages.ts b/projects/demo/src/modules/app/pages.ts index 4bcbd55bd39d..b2566b8f45b0 100644 --- a/projects/demo/src/modules/app/pages.ts +++ b/projects/demo/src/modules/app/pages.ts @@ -1358,6 +1358,12 @@ export const pages: TuiDocPages = [ 'inputMode, labelOutside, size, type, нативные, инпут', route: '/directives/textfield-controller', }, + { + section: 'Tools', + title: 'NumberFormat', + keywords: 'number, format, число, separator, precision, rounding, формат', + route: '/directives/number-format', + }, { section: 'Tools', title: 'Touchable', diff --git a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.component.ts b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.component.ts index 8339b984acf3..f700ab5e2260 100644 --- a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.component.ts +++ b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.component.ts @@ -5,6 +5,7 @@ import {TUI_HINT_DIRECTIONS} from '@taiga-ui/core'; import {AbstractExampleTuiControl} from '../control'; import {AbstractExampleTuiHint} from '../hint'; import {AbstractExampleTuiInteractive} from '../interactive'; +import {AbstractExampleTuiNumberFormat} from '../number-format'; import {ABSTRACT_PROPS_ACCESSOR} from './abstract-props-accessor'; import type {TuiSupportingDocumentationComponent} from './supporting-documentation-component'; @@ -48,4 +49,10 @@ export class InheritedDocumentationComponent { ): documentedComponent is AbstractExampleTuiHint { return documentedComponent instanceof AbstractExampleTuiHint; } + + protected isTuiFormatNumber( + documentedComponent: TuiSupportingDocumentationComponent, + ): documentedComponent is AbstractExampleTuiHint { + return documentedComponent instanceof AbstractExampleTuiNumberFormat; + } } diff --git a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.module.ts b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.module.ts index 0a5c9c8286b3..0da88031a913 100644 --- a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.module.ts +++ b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.module.ts @@ -4,6 +4,7 @@ import {TuiDocDocumentationModule} from '@taiga-ui/addon-doc'; import {DropdownDocumentationModule} from '../dropdown-documentation/dropdown-documentation.module'; import {HintControllerDocumentationModule} from '../hint-controller-documentation/hint-controller-documentation.module'; +import {NumberFormatDocumentationModule} from '../number-format-documentation/number-format-documentation.module'; import {TextfieldControllerDocumentationModule} from '../textfield-controller-documentation/textfield-controller-documentation.module'; import {InheritedDocumentationComponent} from './inherited-documentation.component'; @@ -14,6 +15,7 @@ import {InheritedDocumentationComponent} from './inherited-documentation.compone DropdownDocumentationModule, HintControllerDocumentationModule, TextfieldControllerDocumentationModule, + NumberFormatDocumentationModule, ], declarations: [InheritedDocumentationComponent], exports: [InheritedDocumentationComponent], diff --git a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.template.html b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.template.html index 0fdc1a41fb3c..0a01994d03f5 100644 --- a/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.template.html +++ b/projects/demo/src/modules/components/abstract/inherited-documentation/inherited-documentation.template.html @@ -1,4 +1,5 @@ + diff --git a/projects/demo/src/modules/components/abstract/inherited-documentation/supporting-documentation-component.ts b/projects/demo/src/modules/components/abstract/inherited-documentation/supporting-documentation-component.ts index eb154a3d0492..b1cddbe9183b 100644 --- a/projects/demo/src/modules/components/abstract/inherited-documentation/supporting-documentation-component.ts +++ b/projects/demo/src/modules/components/abstract/inherited-documentation/supporting-documentation-component.ts @@ -1,8 +1,10 @@ import type {AbstractExampleTuiControl} from '../control'; import type {AbstractExampleTuiHint} from '../hint'; import type {AbstractExampleTuiInteractive} from '../interactive'; +import type {AbstractExampleTuiNumberFormat} from '../number-format'; export type TuiSupportingDocumentationComponent = | AbstractExampleTuiControl | AbstractExampleTuiHint - | AbstractExampleTuiInteractive; + | AbstractExampleTuiInteractive + | AbstractExampleTuiNumberFormat; diff --git a/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.component.ts b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.component.ts new file mode 100644 index 000000000000..f41931982de2 --- /dev/null +++ b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.component.ts @@ -0,0 +1,16 @@ +import {Component, inject} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; + +import {ABSTRACT_PROPS_ACCESSOR} from '../inherited-documentation/abstract-props-accessor'; +import type {AbstractExampleTuiNumberFormat} from '../number-format'; + +@Component({ + selector: 'number-format-documentation', + templateUrl: './number-format-documentation.template.html', + changeDetection, +}) +export class NumberFormatDocumentationComponent { + protected readonly documentedComponent = inject( + ABSTRACT_PROPS_ACCESSOR, + ); +} diff --git a/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.module.ts b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.module.ts new file mode 100644 index 000000000000..f462381eef3e --- /dev/null +++ b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.module.ts @@ -0,0 +1,14 @@ +import {CommonModule} from '@angular/common'; +import {NgModule} from '@angular/core'; +import {RouterModule} from '@angular/router'; +import {TuiDocDocumentationModule} from '@taiga-ui/addon-doc'; +import {TuiLinkModule} from '@taiga-ui/core'; + +import {NumberFormatDocumentationComponent} from './number-format-documentation.component'; + +@NgModule({ + imports: [CommonModule, RouterModule, TuiDocDocumentationModule, TuiLinkModule], + declarations: [NumberFormatDocumentationComponent], + exports: [NumberFormatDocumentationComponent], +}) +export class NumberFormatDocumentationModule {} diff --git a/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.template.html b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.template.html new file mode 100644 index 000000000000..d7b32b66215d --- /dev/null +++ b/projects/demo/src/modules/components/abstract/number-format-documentation/number-format-documentation.template.html @@ -0,0 +1,90 @@ +
+ Can be expanded with + + TuiNumberFormat + +
+

+ Usage example: + + [tuiNumberFormat]='{decimalMode, precision, rounding, zeroPadding, thousandSeparator, + decimalSeparator}' + +

+

+ Requires you to import + TuiNumberFormatModule + . +

+ + + +
+
+ always +
+
+ number of digits after + decimalSeparator + is + always + equal to the precision. +
+ +
+ pad +
+
pads trailing zeroes up to precision, if the number is fractional
+ +
+ not-zero +
+
drops trailing zeroes
+
+
+ + Rounding + + + A number of digits after comma ( + Infinity + for an untouched decimal part) + + + Symbol for separating thousands + + + Symbol for separating fraction + +
diff --git a/projects/demo/src/modules/components/abstract/number-format.ts b/projects/demo/src/modules/components/abstract/number-format.ts new file mode 100644 index 000000000000..1829ab6f3800 --- /dev/null +++ b/projects/demo/src/modules/components/abstract/number-format.ts @@ -0,0 +1,24 @@ +import type {TuiRounding} from '@taiga-ui/cdk'; +import type {TuiDecimalMode} from '@taiga-ui/core'; +import {TUI_DEFAULT_NUMBER_FORMAT} from '@taiga-ui/core'; + +import {AbstractExampleTuiControl} from './control'; + +export abstract class AbstractExampleTuiNumberFormat extends AbstractExampleTuiControl { + public precision = TUI_DEFAULT_NUMBER_FORMAT.precision; + + public readonly decimalVariants: TuiDecimalMode[] = ['always', 'pad', 'not-zero']; + public decimalMode = TUI_DEFAULT_NUMBER_FORMAT.decimalMode; + + public readonly roundingVariants: TuiRounding[] = [ + 'truncate', + 'round', + 'ceil', + 'floor', + ]; + + public rounding = TUI_DEFAULT_NUMBER_FORMAT.rounding; + + public decimalSeparator = TUI_DEFAULT_NUMBER_FORMAT.decimalSeparator; + public thousandSeparator = TUI_DEFAULT_NUMBER_FORMAT.thousandSeparator; +} diff --git a/projects/demo/src/modules/components/dialog/examples/4/index.html b/projects/demo/src/modules/components/dialog/examples/4/index.html index 41293efe6003..9e3521ec9d28 100644 --- a/projects/demo/src/modules/components/dialog/examples/4/index.html +++ b/projects/demo/src/modules/components/dialog/examples/4/index.html @@ -43,7 +43,7 @@

Sushi

{{ 300 | tuiAmount: 'RUB' | async }} diff --git a/projects/demo/src/modules/components/input-number/examples/3/index.html b/projects/demo/src/modules/components/input-number/examples/3/index.html index b4f3e412c66b..283cdc468023 100644 --- a/projects/demo/src/modules/components/input-number/examples/3/index.html +++ b/projects/demo/src/modules/components/input-number/examples/3/index.html @@ -2,7 +2,7 @@ π -value diff --git a/projects/demo/src/modules/components/input-number/examples/5/index.html b/projects/demo/src/modules/components/input-number/examples/5/index.html index 84086ea50029..89cd5b19c742 100644 --- a/projects/demo/src/modules/components/input-number/examples/5/index.html +++ b/projects/demo/src/modules/components/input-number/examples/5/index.html @@ -1,7 +1,7 @@ Type a sum diff --git a/projects/demo/src/modules/components/input-number/examples/6/index.ts b/projects/demo/src/modules/components/input-number/examples/6/index.ts index d1497ad28564..dc4c5aee9d00 100644 --- a/projects/demo/src/modules/components/input-number/examples/6/index.ts +++ b/projects/demo/src/modules/components/input-number/examples/6/index.ts @@ -10,7 +10,7 @@ import {tuiInputNumberOptionsProvider} from '@taiga-ui/kit'; changeDetection, providers: [ tuiInputNumberOptionsProvider({ - decimal: 'never', + precision: 0, step: 1, }), ], diff --git a/projects/demo/src/modules/components/input-number/input-number.component.ts b/projects/demo/src/modules/components/input-number/input-number.component.ts index 62eaffd0cb34..907e0f0b1c3a 100644 --- a/projects/demo/src/modules/components/input-number/input-number.component.ts +++ b/projects/demo/src/modules/components/input-number/input-number.component.ts @@ -2,10 +2,9 @@ import {Component, forwardRef} from '@angular/core'; import {FormControl, Validators} from '@angular/forms'; import {changeDetection} from '@demo/emulate/change-detection'; import type {TuiDocExample} from '@taiga-ui/addon-doc'; -import type {TuiDecimal} from '@taiga-ui/core'; -import {AbstractExampleTuiControl} from '../abstract/control'; import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstract-props-accessor'; +import {AbstractExampleTuiNumberFormat} from '../abstract/number-format'; @Component({ selector: 'example-tui-input-number', @@ -18,8 +17,9 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr }, ], }) -export class ExampleTuiInputNumberComponent extends AbstractExampleTuiControl { +export class ExampleTuiInputNumberComponent extends AbstractExampleTuiNumberFormat { public override cleaner = false; + public override precision = 2; public readonly control = new FormControl(6432, Validators.required); @@ -73,17 +73,5 @@ export class ExampleTuiInputNumberComponent extends AbstractExampleTuiControl { protected max = this.maxVariants[0]; - protected readonly decimalVariants: readonly TuiDecimal[] = [ - 'not-zero', - 'always', - 'never', - ]; - - protected decimal = this.decimalVariants[0]; - - protected readonly precisionVariants: readonly number[] = [2, 3, 4, Infinity]; - - protected precision = this.precisionVariants[0]; - protected step = 0; } diff --git a/projects/demo/src/modules/components/input-number/input-number.module.ts b/projects/demo/src/modules/components/input-number/input-number.module.ts index c5f7e26c0c92..d93bb682e731 100644 --- a/projects/demo/src/modules/components/input-number/input-number.module.ts +++ b/projects/demo/src/modules/components/input-number/input-number.module.ts @@ -9,6 +9,7 @@ import { TuiHintModule, TuiLinkModule, TuiNotificationModule, + TuiNumberFormatModule, TuiSvgModule, TuiTextfieldControllerModule, } from '@taiga-ui/core'; @@ -41,6 +42,7 @@ import {ExampleTuiInputNumberComponent} from './input-number.component'; InheritedDocumentationModule, TuiHintModule, RouterModule.forChild(tuiGenerateRoutes(ExampleTuiInputNumberComponent)), + TuiNumberFormatModule, ], declarations: [ ExampleTuiInputNumberComponent, diff --git a/projects/demo/src/modules/components/input-number/input-number.template.html b/projects/demo/src/modules/components/input-number/input-number.template.html index d95f08d08ebd..5880afab7d07 100644 --- a/projects/demo/src/modules/components/input-number/input-number.template.html +++ b/projects/demo/src/modules/components/input-number/input-number.template.html @@ -158,12 +158,10 @@

There are also other components to input numbers:

There are also other components to input numbers: [tuiHintAppearance]="hintAppearance" [tuiHintContent]="hintContent" [tuiHintDirection]="hintDirection" + [tuiNumberFormat]="{ + precision, + decimalMode: decimalMode, + rounding, + thousandSeparator, + decimalSeparator + }" [tuiTextfieldCleaner]="cleaner" [tuiTextfieldCustomContent]="customContent" [tuiTextfieldFiller]="filler" @@ -215,26 +220,6 @@

There are also other components to input numbers:

> Max value
- - A number of digits after comma ( - Infinity - for an untouched decimal part) - - - Show/hide decimal - ExampleTuiInputRangeComponent), }, + tuiDocExcludeProperties(['precision']), ], }) -export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { +export class ExampleTuiInputRangeComponent extends AbstractExampleTuiNumberFormat { public control = new FormControl([0, 10]); public override sizeVariants: readonly TuiSizeL[] = ['m', 'l']; diff --git a/projects/demo/src/modules/components/input-range/input-range.module.ts b/projects/demo/src/modules/components/input-range/input-range.module.ts index 50362d3820d7..542c8d4c568b 100644 --- a/projects/demo/src/modules/components/input-range/input-range.module.ts +++ b/projects/demo/src/modules/components/input-range/input-range.module.ts @@ -7,6 +7,7 @@ import { TuiButtonModule, TuiLinkModule, TuiNotificationModule, + TuiNumberFormatModule, TuiSvgModule, TuiTextfieldControllerModule, } from '@taiga-ui/core'; @@ -17,6 +18,7 @@ import { } from '@taiga-ui/kit'; import {InheritedDocumentationModule} from '../abstract/inherited-documentation/inherited-documentation.module'; +import {NumberFormatDocumentationModule} from '../abstract/number-format-documentation/number-format-documentation.module'; import {TuiInputRangeExample1} from './examples/1'; import {TuiInputRangeExample2} from './examples/2'; import {TuiInputRangeExample3} from './examples/3'; @@ -41,7 +43,9 @@ import {ExampleTuiInputRangeComponent} from './input-range.component'; TuiTextfieldControllerModule, TuiSvgModule, TuiNotificationModule, + TuiNumberFormatModule, RouterModule.forChild(tuiGenerateRoutes(ExampleTuiInputRangeComponent)), + NumberFormatDocumentationModule, ], declarations: [ ExampleTuiInputRangeComponent, diff --git a/projects/demo/src/modules/components/input-range/input-range.template.html b/projects/demo/src/modules/components/input-range/input-range.template.html index f89f2cb6ed85..5ff124253520 100644 --- a/projects/demo/src/modules/components/input-range/input-range.template.html +++ b/projects/demo/src/modules/components/input-range/input-range.template.html @@ -123,6 +123,7 @@ [rightValueContent]="rightValueContent" [segments]="segments" [steps]="steps" + [tuiNumberFormat]="{decimalMode: decimalMode, rounding, thousandSeparator, decimalSeparator}" [tuiTextfieldLabelOutside]="labelOutside" [tuiTextfieldSize]="size" > @@ -283,6 +284,7 @@
Size + diff --git a/projects/demo/src/modules/components/input-slider/input-slider.component.ts b/projects/demo/src/modules/components/input-slider/input-slider.component.ts index 30a03d299033..9d5caeab2c93 100644 --- a/projects/demo/src/modules/components/input-slider/input-slider.component.ts +++ b/projects/demo/src/modules/components/input-slider/input-slider.component.ts @@ -2,12 +2,13 @@ import {Component, forwardRef} from '@angular/core'; import {FormControl} from '@angular/forms'; import {changeDetection} from '@demo/emulate/change-detection'; import type {TuiDocExample} from '@taiga-ui/addon-doc'; +import {tuiDocExcludeProperties} from '@taiga-ui/addon-doc'; import type {TuiContext} from '@taiga-ui/cdk'; import type {TuiSizeL} from '@taiga-ui/core'; import type {TuiKeySteps} from '@taiga-ui/kit'; -import {AbstractExampleTuiControl} from '../abstract/control'; import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstract-props-accessor'; +import {AbstractExampleTuiNumberFormat} from '../abstract/number-format'; @Component({ selector: 'example-tui-input-slider', @@ -18,9 +19,10 @@ import {ABSTRACT_PROPS_ACCESSOR} from '../abstract/inherited-documentation/abstr provide: ABSTRACT_PROPS_ACCESSOR, useExisting: forwardRef(() => ExampleTuiInputSliderComponent), }, + tuiDocExcludeProperties(['precision']), ], }) -export class ExampleTuiInputSliderComponent extends AbstractExampleTuiControl { +export class ExampleTuiInputSliderComponent extends AbstractExampleTuiNumberFormat { public override readonly sizeVariants: readonly TuiSizeL[] = ['m', 'l']; public override size = this.sizeVariants[1]; public readonly control = new FormControl(0); diff --git a/projects/demo/src/modules/components/input-slider/input-slider.module.ts b/projects/demo/src/modules/components/input-slider/input-slider.module.ts index b311c88e9244..ff7c6b4d641f 100644 --- a/projects/demo/src/modules/components/input-slider/input-slider.module.ts +++ b/projects/demo/src/modules/components/input-slider/input-slider.module.ts @@ -8,6 +8,7 @@ import { TuiHintModule, TuiLinkModule, TuiNotificationModule, + TuiNumberFormatModule, TuiSvgModule, TuiTextfieldControllerModule, } from '@taiga-ui/core'; @@ -41,6 +42,7 @@ import {ExampleTuiInputSliderComponent} from './input-slider.component'; TuiSvgModule, TuiNotificationModule, TuiTextfieldControllerModule, + TuiNumberFormatModule, RouterModule.forChild(tuiGenerateRoutes(ExampleTuiInputSliderComponent)), ], declarations: [ diff --git a/projects/demo/src/modules/components/input-slider/input-slider.template.html b/projects/demo/src/modules/components/input-slider/input-slider.template.html index b4fe3a6d3c4f..c2bb123784e1 100644 --- a/projects/demo/src/modules/components/input-slider/input-slider.template.html +++ b/projects/demo/src/modules/components/input-slider/input-slider.template.html @@ -114,6 +114,7 @@ [tuiHintAppearance]="hintAppearance" [tuiHintContent]="hintContent" [tuiHintDirection]="hintDirection" + [tuiNumberFormat]="{decimalMode: decimalMode, rounding, thousandSeparator, decimalSeparator}" [tuiTextfieldCleaner]="cleaner" [tuiTextfieldCustomContent]="customContentSelected" [tuiTextfieldIconLeft]="iconLeft" diff --git a/projects/demo/src/modules/components/select/examples/9/account/my-account.component.html b/projects/demo/src/modules/components/select/examples/9/account/my-account.component.html index afefa4810926..f853dc821f88 100644 --- a/projects/demo/src/modules/components/select/examples/9/account/my-account.component.html +++ b/projects/demo/src/modules/components/select/examples/9/account/my-account.component.html @@ -10,7 +10,7 @@ {{ account.name }} {{ account.amount | tuiAmount: account.currency | async }} diff --git a/projects/demo/src/modules/directives/number-format/examples/1/index.html b/projects/demo/src/modules/directives/number-format/examples/1/index.html new file mode 100644 index 000000000000..7d9c182c29a2 --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/examples/1/index.html @@ -0,0 +1,14 @@ + +
+ + + Cool + + +
diff --git a/projects/demo/src/modules/directives/number-format/examples/1/index.ts b/projects/demo/src/modules/directives/number-format/examples/1/index.ts new file mode 100644 index 000000000000..ae874db0e282 --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/examples/1/index.ts @@ -0,0 +1,18 @@ +import {Component} from '@angular/core'; +import {FormControl, ReactiveFormsModule} from '@angular/forms'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {encapsulation} from '@demo/emulate/encapsulation'; +import {TuiNumberFormatModule} from '@taiga-ui/core'; +import {TuiInputNumberModule} from '@taiga-ui/kit'; + +@Component({ + standalone: true, + selector: 'tui-number-format-example-1', + imports: [TuiInputNumberModule, TuiNumberFormatModule, ReactiveFormsModule], + templateUrl: './index.html', + encapsulation, + changeDetection, +}) +export class TuiNumberFormatExample1 { + protected readonly control = new FormControl(120.234); +} diff --git a/projects/demo/src/modules/directives/number-format/examples/import/import-module.md b/projects/demo/src/modules/directives/number-format/examples/import/import-module.md new file mode 100644 index 000000000000..45dfb4c1ab6e --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/examples/import/import-module.md @@ -0,0 +1,15 @@ +```ts +import {TuiNumberFormatModule} from '@taiga-ui/core'; + +// ... + +@Component({ + standalone: true, + imports: [ + // ... + TuiNumberFormatModule, + ], + // ... +}) +export class MyComponent {} +``` diff --git a/projects/demo/src/modules/directives/number-format/examples/import/insert-template.md b/projects/demo/src/modules/directives/number-format/examples/import/insert-template.md new file mode 100644 index 000000000000..0785baafc356 --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/examples/import/insert-template.md @@ -0,0 +1,5 @@ +```html + +``` diff --git a/projects/demo/src/modules/directives/number-format/number-format.component.ts b/projects/demo/src/modules/directives/number-format/number-format.component.ts new file mode 100644 index 000000000000..a8a583758dbe --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/number-format.component.ts @@ -0,0 +1,25 @@ +import {AsyncPipe} from '@angular/common'; +import {Component} from '@angular/core'; +import {changeDetection} from '@demo/emulate/change-detection'; +import {TuiExamplePipe, TuiSetupComponent} from '@demo/utils'; +import {TuiAddonDocModule} from '@taiga-ui/addon-doc'; + +import {TuiNumberFormatExample1} from './examples/1'; + +@Component({ + standalone: true, + selector: 'example-tui-number-format', + imports: [ + TuiExamplePipe, + TuiSetupComponent, + AsyncPipe, + TuiAddonDocModule, + TuiNumberFormatExample1, + ], + templateUrl: './number-format.template.html', + changeDetection, +}) +export default class ExampleTuiNumberFormatComponent { + protected readonly import = import('./examples/import/import-module.md?raw'); + protected readonly template = import('./examples/import/insert-template.md?raw'); +} diff --git a/projects/demo/src/modules/directives/number-format/number-format.template.html b/projects/demo/src/modules/directives/number-format/number-format.template.html new file mode 100644 index 000000000000..befd489277ca --- /dev/null +++ b/projects/demo/src/modules/directives/number-format/number-format.template.html @@ -0,0 +1,32 @@ + + +

+ Directive allows to customize + TuiInputNumber + , + TuiInputSlider + , + TuiInputRange + number format. +

+ + + + +
+ + + + +
diff --git a/projects/demo/src/modules/pipes/amount/examples/2/index.html b/projects/demo/src/modules/pipes/amount/examples/2/index.html index 7b9286862c4a..605d7ca4d09d 100644 --- a/projects/demo/src/modules/pipes/amount/examples/2/index.html +++ b/projects/demo/src/modules/pipes/amount/examples/2/index.html @@ -4,6 +4,10 @@
{{ 200.536 | tuiAmount: 'EUR' | async }}
-
+
{{ 54000.643 | tuiAmount: 'USD' : 'left' | async }}
+ +
+ {{ 800 | tuiAmount: 'USD' : 'left' | async }} +
diff --git a/projects/demo/src/modules/pipes/format-number/examples/1/index.html b/projects/demo/src/modules/pipes/format-number/examples/1/index.html index 6d1103156204..7bf7dde5e3c3 100644 --- a/projects/demo/src/modules/pipes/format-number/examples/1/index.html +++ b/projects/demo/src/modules/pipes/format-number/examples/1/index.html @@ -2,10 +2,10 @@

Formatted number with custom params: - {{ 10500.33 | tuiFormatNumber: {decimalLimit: 4, decimalSeparator: '.'} | async }} + {{ 10500.33 | tuiFormatNumber: {precision: 4, decimalSeparator: '.'} | async }}

Formatted number with rounding: - {{ 10500.334 | tuiFormatNumber: {decimalLimit: 2, decimalSeparator: '.', rounding: 'ceil'} | async }} + {{ 10500.334 | tuiFormatNumber: {precision: 2, decimalSeparator: '.', rounding: 'ceil'} | async }}

diff --git a/projects/demo/src/modules/pipes/format-number/format-number.component.ts b/projects/demo/src/modules/pipes/format-number/format-number.component.ts index c203b333a04c..b18ae8675e7e 100644 --- a/projects/demo/src/modules/pipes/format-number/format-number.component.ts +++ b/projects/demo/src/modules/pipes/format-number/format-number.component.ts @@ -1,15 +1,26 @@ -import {Component} from '@angular/core'; +import {Component, forwardRef} from '@angular/core'; +import {FormControl} from '@angular/forms'; import {changeDetection} from '@demo/emulate/change-detection'; import type {TuiDocExample} from '@taiga-ui/addon-doc'; -import type {TuiDecimalSymbol} from '@taiga-ui/core'; + +import {ABSTRACT_PROPS_ACCESSOR} from '../../components/abstract/inherited-documentation/abstract-props-accessor'; +import {AbstractExampleTuiNumberFormat} from '../../components/abstract/number-format'; @Component({ selector: 'example-tui-format-number', templateUrl: './format-number.template.html', styleUrls: ['./format-number.style.less'], changeDetection, + providers: [ + { + provide: ABSTRACT_PROPS_ACCESSOR, + useExisting: forwardRef(() => ExampleTuiFormatNumberComponent), + }, + ], }) -export class ExampleTuiFormatNumberComponent { +export class ExampleTuiFormatNumberComponent extends AbstractExampleTuiNumberFormat { + public readonly control = new FormControl(100); + protected readonly exampleModule = import('./examples/import/import-module.md?raw'); protected readonly exampleHtml = import('./examples/import/insert-template.md?raw'); @@ -17,12 +28,4 @@ export class ExampleTuiFormatNumberComponent { TypeScript: import('./examples/1/index.ts?raw'), HTML: import('./examples/1/index.html?raw'), }; - - protected value = 100; - - protected readonly decimalLimitVariants = [Infinity, 0, 2, 4]; - protected decimalLimit = this.decimalLimitVariants[0]; - - protected readonly decimalSeparatorVariants: TuiDecimalSymbol[] = [',', '.']; - protected decimalSeparator: TuiDecimalSymbol = this.decimalSeparatorVariants[0]; } diff --git a/projects/demo/src/modules/pipes/format-number/format-number.module.ts b/projects/demo/src/modules/pipes/format-number/format-number.module.ts index 091e3ba6f3d1..74265332f774 100644 --- a/projects/demo/src/modules/pipes/format-number/format-number.module.ts +++ b/projects/demo/src/modules/pipes/format-number/format-number.module.ts @@ -1,30 +1,29 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; -import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {ReactiveFormsModule} from '@angular/forms'; import {RouterModule} from '@angular/router'; +import {TuiExamplePipe} from '@demo/utils'; import {TuiAddonDocModule, tuiGenerateRoutes} from '@taiga-ui/addon-doc'; -import { - TuiFormatNumberPipeModule, - TuiLinkModule, - TuiTextfieldControllerModule, -} from '@taiga-ui/core'; -import {TuiInputSliderModule, TuiRadioListModule} from '@taiga-ui/kit'; +import {TuiFormatNumberPipeModule, TuiTextfieldControllerModule} from '@taiga-ui/core'; +import {TuiInputNumberModule} from '@taiga-ui/kit'; +import {InheritedDocumentationModule} from '../../components/abstract/inherited-documentation/inherited-documentation.module'; +import {NumberFormatDocumentationModule} from '../../components/abstract/number-format-documentation/number-format-documentation.module'; import {TuiFormatNumberExample1} from './examples/1'; import {ExampleTuiFormatNumberComponent} from './format-number.component'; @NgModule({ imports: [ TuiFormatNumberPipeModule, - TuiInputSliderModule, + TuiExamplePipe, ReactiveFormsModule, - FormsModule, CommonModule, - TuiRadioListModule, + TuiTextfieldControllerModule, + TuiInputNumberModule, TuiAddonDocModule, - TuiLinkModule, RouterModule.forChild(tuiGenerateRoutes(ExampleTuiFormatNumberComponent)), - TuiTextfieldControllerModule, + InheritedDocumentationModule, + NumberFormatDocumentationModule, ], declarations: [ExampleTuiFormatNumberComponent, TuiFormatNumberExample1], exports: [ExampleTuiFormatNumberComponent], diff --git a/projects/demo/src/modules/pipes/format-number/format-number.style.less b/projects/demo/src/modules/pipes/format-number/format-number.style.less index 8baf395fd4d3..ab00e8ba16df 100644 --- a/projects/demo/src/modules/pipes/format-number/format-number.style.less +++ b/projects/demo/src/modules/pipes/format-number/format-number.style.less @@ -2,7 +2,7 @@ font-size: 1.1875rem; } -.slider { +.input-number { margin-top: 0.75rem; width: 9.375rem; } diff --git a/projects/demo/src/modules/pipes/format-number/format-number.template.html b/projects/demo/src/modules/pipes/format-number/format-number.template.html index 7439119a0e24..2ad30fb77d55 100644 --- a/projects/demo/src/modules/pipes/format-number/format-number.template.html +++ b/projects/demo/src/modules/pipes/format-number/format-number.template.html @@ -29,36 +29,20 @@

Formatted number: - {{ value | tuiFormatNumber: {decimalLimit, decimalSeparator} | async }} + {{ + control.value ?? 0 + | tuiFormatNumber + : {precision, decimalMode: decimalMode, rounding, thousandSeparator, decimalSeparator} + | async + }}

- - - - Digits after comma (use - Infinity - not to change) - - - Symbol for separating fraction - - +
diff --git a/projects/demo/src/modules/utils/format/examples/5/index.html b/projects/demo/src/modules/utils/format/examples/5/index.html index 805fb731feff..4772ae8c7d10 100644 --- a/projects/demo/src/modules/utils/format/examples/5/index.html +++ b/projects/demo/src/modules/utils/format/examples/5/index.html @@ -1,4 +1,4 @@ -'{{ formattedNumber }}' = tuiFormatNumber(value, decimalLimit, decimalSeparator, thousandSeparator); +'{{ formattedNumber }}' = tuiFormatNumber(value, precision, decimalSeparator, thousandSeparator);
@@ -9,10 +9,10 @@ value - decimalLimit + precision ('.'), thousandSeparator: new FormControl(' '), }); protected get formattedNumber(): string { - const {value, decimalLimit, decimalSeparator, thousandSeparator} = + const {value, precision, decimalSeparator, thousandSeparator} = this.parametersForm.value; return tuiFormatNumber(value ?? 123456.789, { - decimalLimit: decimalLimit ?? 2, + precision: precision ?? 2, decimalSeparator: decimalSeparator ?? '.', thousandSeparator: thousandSeparator ?? ' ', }); diff --git a/projects/demo/src/modules/utils/math/examples/1/index.html b/projects/demo/src/modules/utils/math/examples/1/index.html index 032757f88659..42d299a0c6b7 100644 --- a/projects/demo/src/modules/utils/math/examples/1/index.html +++ b/projects/demo/src/modules/utils/math/examples/1/index.html @@ -7,7 +7,7 @@ value diff --git a/projects/demo/src/modules/utils/math/math.module.ts b/projects/demo/src/modules/utils/math/math.module.ts index 71ff4d4dcabb..447d65d1fbd7 100644 --- a/projects/demo/src/modules/utils/math/math.module.ts +++ b/projects/demo/src/modules/utils/math/math.module.ts @@ -3,6 +3,7 @@ import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {RouterModule} from '@angular/router'; import {TuiAddonDocModule, tuiGenerateRoutes} from '@taiga-ui/addon-doc'; +import {TuiNumberFormatModule} from '@taiga-ui/core'; import {TuiInputNumberModule} from '@taiga-ui/kit'; import {TuiMathExample1} from './examples/1'; @@ -20,6 +21,7 @@ import {ExampleMathComponent} from './math.component'; ReactiveFormsModule, TuiAddonDocModule, RouterModule.forChild(tuiGenerateRoutes(ExampleMathComponent)), + TuiNumberFormatModule, ], declarations: [ ExampleMathComponent, diff --git a/projects/kit/components/input-number/input-number.component.ts b/projects/kit/components/input-number/input-number.component.ts index 40ffb2aa3549..a30d754aa01d 100644 --- a/projects/kit/components/input-number/input-number.component.ts +++ b/projects/kit/components/input-number/input-number.component.ts @@ -33,7 +33,7 @@ import { tuiPure, tuiWatch, } from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiSizeL, TuiSizeS} from '@taiga-ui/core'; +import type {TuiDecimalMode, TuiSizeL, TuiSizeS} from '@taiga-ui/core'; import { TEXTFIELD_CONTROLLER_PROVIDER, TUI_DEFAULT_NUMBER_FORMAT, @@ -41,7 +41,6 @@ import { TUI_TEXTFIELD_SIZE, TUI_TEXTFIELD_WATCHED_CONTROLLER, tuiFormatNumber, - tuiGetFractionPartPadded, TuiPrimitiveTextfieldComponent, } from '@taiga-ui/core'; import {PolymorpheusOutletDirective} from '@tinkoff/ng-polymorpheus'; @@ -85,12 +84,6 @@ export class TuiInputNumberComponent @Input() public max: number | null = this.options.max; - @Input() - public decimal = this.options.decimal; - - @Input() - public precision = this.options.precision; - @Input() public step = this.options.step; @@ -125,12 +118,12 @@ export class TuiInputNumberComponent return 'text'; } - return this.decimal === 'never' ? 'numeric' : 'decimal'; + return !this.precision ? 'numeric' : 'decimal'; } public get calculatedMaxLength(): number { const decimalPart = - this.decimal !== 'never' && + !!this.precision && this.nativeValue.includes(this.numberFormat.decimalSeparator); const precision = decimalPart ? Math.min(this.precision + 1, 20) : 0; const takeThousand = this.numberFormat.thousandSeparator.repeat(5).length; @@ -220,7 +213,7 @@ export class TuiInputNumberComponent protected get mask(): MaskitoOptions { return this.calculateMask( this.precision, - this.decimal, + this.numberFormat.decimalMode, this.numberFormat.decimalSeparator, this.numberFormat.thousandSeparator, this.computedMin, @@ -281,26 +274,11 @@ export class TuiInputNumberComponent } protected getFormattedValue(value: number): string { - const absValue = Math.abs(value); - const hasFraction = absValue % 1 > 0; - let decimalLimit = - this.decimal === 'always' || (hasFraction && this.decimal !== 'never') - ? this.precision - : 0; - - const fraction = hasFraction - ? tuiGetFractionPartPadded(value, this.precision) - : ''; - - if (this.focused && this.decimal !== 'always') { - decimalLimit = fraction.length; - } - return ( this.computedPrefix + tuiFormatNumber(value, { ...this.numberFormat, - decimalLimit, + precision: this.precision, }).replace(CHAR_HYPHEN, CHAR_MINUS) + this.computedPostfix ); @@ -318,6 +296,12 @@ export class TuiInputNumberComponent return maskitoParseNumber(this.nativeValue, this.numberFormat.decimalSeparator); } + private get precision(): number { + return Number.isNaN(this.numberFormat.precision) + ? 2 + : this.numberFormat.precision; + } + @tuiPure private computeMin(min: number | null, max: number | null): number { return Math.min( @@ -337,7 +321,7 @@ export class TuiInputNumberComponent @tuiPure private calculateMask( precision: number, - decimalMode: TuiDecimal, + decimalMode: TuiDecimalMode, decimalSeparator: string, thousandSeparator: string, min: number, @@ -352,7 +336,7 @@ export class TuiInputNumberComponent max, prefix, postfix, - precision: decimalMode === 'never' ? 0 : precision, + precision, decimalZeroPadding: decimalMode === 'always', }; const {plugins, ...options} = maskitoNumberOptionsGenerator(generatorParams); diff --git a/projects/kit/components/input-number/input-number.options.ts b/projects/kit/components/input-number/input-number.options.ts index 256fccbfdf20..fec2eaae6d30 100644 --- a/projects/kit/components/input-number/input-number.options.ts +++ b/projects/kit/components/input-number/input-number.options.ts @@ -1,10 +1,10 @@ import type {Provider} from '@angular/core'; import {tuiCreateToken, tuiProvideOptions} from '@taiga-ui/cdk'; -import type {TuiDecimal} from '@taiga-ui/core'; +import type {TuiDecimalMode} from '@taiga-ui/core'; import type {PolymorpheusContent} from '@tinkoff/ng-polymorpheus'; export interface TuiInputNumberOptions { - readonly decimal: TuiDecimal; + readonly decimal: TuiDecimalMode; readonly icons: Readonly<{ down: PolymorpheusContent; up: PolymorpheusContent; diff --git a/projects/kit/components/input-number/test/input-number-format.spec.ts b/projects/kit/components/input-number/test/input-number-format.spec.ts index c5cb567611c3..d3c41f5e0f5f 100644 --- a/projects/kit/components/input-number/test/input-number-format.spec.ts +++ b/projects/kit/components/input-number/test/input-number-format.spec.ts @@ -4,8 +4,8 @@ import {TestBed} from '@angular/core/testing'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk'; -import type {TuiDecimal} from '@taiga-ui/core'; -import {tuiNumberFormatProvider} from '@taiga-ui/core'; +import type {TuiDecimalMode} from '@taiga-ui/core'; +import {TuiNumberFormatModule, tuiNumberFormatProvider} from '@taiga-ui/core'; import {TuiInputNumberComponent, TuiInputNumberModule} from '@taiga-ui/kit'; import {TuiNativeInputPO} from '@taiga-ui/testing'; @@ -15,8 +15,7 @@ describe('InputNumber - backward compatibility for separators', () => { `, @@ -28,7 +27,7 @@ describe('InputNumber - backward compatibility for separators', () => { public control = new FormControl(12345.0); public form = new FormGroup({control: this.control}); - public decimal: TuiDecimal = 'always'; + public decimalMode: TuiDecimalMode = 'always'; public precision = 2; } @@ -42,6 +41,7 @@ describe('InputNumber - backward compatibility for separators', () => { TestBed.configureTestingModule({ imports: [ NoopAnimationsModule, + TuiNumberFormatModule, TuiInputNumberModule, ReactiveFormsModule, ], @@ -81,6 +81,7 @@ describe('InputNumber - backward compatibility for separators', () => { imports: [ NoopAnimationsModule, TuiInputNumberModule, + TuiNumberFormatModule, ReactiveFormsModule, ], declarations: [TestComponent], diff --git a/projects/kit/components/input-number/test/input-number.component.spec.ts b/projects/kit/components/input-number/test/input-number.component.spec.ts index af207b2b9e90..580e2dc3cfaa 100644 --- a/projects/kit/components/input-number/test/input-number.component.spec.ts +++ b/projects/kit/components/input-number/test/input-number.component.spec.ts @@ -5,8 +5,12 @@ import {TestBed} from '@angular/core/testing'; import {FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; import {CHAR_MINUS, CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiSizeL, TuiSizeS} from '@taiga-ui/core'; -import {TuiHintModule, TuiTextfieldControllerModule} from '@taiga-ui/core'; +import type {TuiDecimalMode, TuiSizeL, TuiSizeS} from '@taiga-ui/core'; +import { + TuiHintModule, + TuiNumberFormatModule, + TuiTextfieldControllerModule, +} from '@taiga-ui/core'; import {TuiInputNumberComponent, TuiInputNumberModule} from '@taiga-ui/kit'; import {TuiNativeInputPO, TuiPageObject} from '@taiga-ui/testing'; @@ -17,9 +21,9 @@ describe('InputNumber', () => { @@ -42,7 +46,8 @@ describe('InputNumber', () => { }); public readOnly = false; - public decimal: TuiDecimal = 'never'; + public decimalMode: TuiDecimalMode = 'pad'; + public precision = NaN; public cleaner = true; public defaultValues = false; public size: TuiSizeL | TuiSizeS = 'm'; @@ -60,6 +65,7 @@ describe('InputNumber', () => { imports: [ NoopAnimationsModule, TuiInputNumberModule, + TuiNumberFormatModule, ReactiveFormsModule, TuiTextfieldControllerModule, TuiHintModule, @@ -126,8 +132,9 @@ describe('InputNumber', () => { }); }); - it("Non-zero pennies are not shown when decimal = 'never'", async () => { + it('Non-zero pennies are not shown when precision = 0', async () => { testComponent.control.setValue(12.3); + testComponent.precision = 0; fixture.detectChanges(); await fixture.whenStable(); @@ -188,7 +195,7 @@ describe('InputNumber', () => { }); it('Value does not depend on the separator', () => { - testComponent.decimal = 'not-zero'; + testComponent.decimalMode = 'not-zero'; inputPO.sendText('123456,50'); expect(testComponent.control.value).toBe(123456.5); @@ -257,7 +264,7 @@ describe('InputNumber', () => { }); it('The correctly filled value is passed to the form number', () => { - testComponent.component.decimal = 'not-zero'; + testComponent.decimalMode = 'not-zero'; inputPO.sendText(`-12${CHAR_NO_BREAK_SPACE}345,67`); expect(testComponent.control.value).toBe(-12345.67); @@ -266,6 +273,8 @@ describe('InputNumber', () => { describe('computedValue | value to display', () => { it('The given value from the form is correctly converted to a string', () => { + testComponent.precision = 0; + fixture.detectChanges(); testComponent.control.setValue(-12345.67); expect(component.computedValue).toBe( @@ -290,7 +299,7 @@ describe('InputNumber', () => { }); it("Doesn't trim zeros if the input is focused", () => { - component.decimal = 'not-zero'; + testComponent.decimalMode = 'not-zero'; inputPO.focus(); inputPO.sendText('10,07'); @@ -300,7 +309,7 @@ describe('InputNumber', () => { }); it('formats a value if the element is out of focus', () => { - component.decimal = 'not-zero'; + testComponent.decimalMode = 'not-zero'; inputPO.sendTextAndBlur('10,0'); @@ -314,8 +323,8 @@ describe('InputNumber', () => { describe('Format value when element lose focus with precision > 6', () => { beforeEach(() => { - component.decimal = 'always'; - component.precision = 10; + testComponent.decimalMode = 'always'; + testComponent.precision = 10; inputPO.sendText(''); inputPO.focus(); }); @@ -349,13 +358,13 @@ describe('InputNumber', () => { expect(nativeInput.getAttribute('maxlength')).toBe('23'); }); - describe('When decimal === always', () => { + describe('When decimalMode === always', () => { it('Adds the number of zeros specified by the precision property when updating Value (123) with an integer', () => { const value = '123'; const precision = 2; - component.decimal = 'always'; - component.precision = precision; + testComponent.decimalMode = 'always'; + testComponent.precision = precision; inputPO.sendText(value); inputPO.blur(); @@ -366,8 +375,8 @@ describe('InputNumber', () => { const value = '0'; const precision = 2; - component.decimal = 'always'; - component.precision = precision; + testComponent.decimalMode = 'always'; + testComponent.precision = precision; inputPO.sendText(value); inputPO.blur(); diff --git a/projects/kit/components/input-range/input-range.component.ts b/projects/kit/components/input-range/input-range.component.ts index eace36a526b0..54b09f3571ea 100644 --- a/projects/kit/components/input-range/input-range.component.ts +++ b/projects/kit/components/input-range/input-range.component.ts @@ -25,7 +25,7 @@ import { tuiPure, tuiRound, } from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiWithOptionalMinMax} from '@taiga-ui/core'; +import type {TuiWithOptionalMinMax} from '@taiga-ui/core'; import { TEXTFIELD_CONTROLLER_PROVIDER, TUI_TEXTFIELD_WATCHED_CONTROLLER, @@ -145,10 +145,6 @@ export class TuiInputRangeComponent return tuiGetFractionPartPadded(this.quantum).length; } - protected get decimal(): TuiDecimal { - return this.precision ? 'not-zero' : 'never'; - } - protected get computedSteps(): number { return this.steps || (this.max - this.min) / this.quantum; } diff --git a/projects/kit/components/input-range/input-range.module.ts b/projects/kit/components/input-range/input-range.module.ts index bee839ec7006..63b690693d29 100644 --- a/projects/kit/components/input-range/input-range.module.ts +++ b/projects/kit/components/input-range/input-range.module.ts @@ -2,7 +2,11 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {TuiActiveZoneModule, TuiPressedModule} from '@taiga-ui/cdk'; -import {TuiTextfieldControllerModule, TuiWrapperModule} from '@taiga-ui/core'; +import { + TuiNumberFormatModule, + TuiTextfieldControllerModule, + TuiWrapperModule, +} from '@taiga-ui/core'; import {TuiInputNumberModule} from '@taiga-ui/kit/components/input-number'; import {TuiRangeModule} from '@taiga-ui/kit/components/range'; import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus'; @@ -20,6 +24,7 @@ import {TuiInputRangeComponent} from './input-range.component'; TuiRangeModule, TuiWrapperModule, TuiTextfieldControllerModule, + TuiNumberFormatModule, ], declarations: [TuiInputRangeComponent], exports: [TuiInputRangeComponent], diff --git a/projects/kit/components/input-range/input-range.template.html b/projects/kit/components/input-range/input-range.template.html index 2af83537f591..cba71f9dcfe8 100644 --- a/projects/kit/components/input-range/input-range.template.html +++ b/projects/kit/components/input-range/input-range.template.html @@ -13,12 +13,11 @@ automation-id="tui-input-range__left-input" tuiTextfieldAppearance="none" class="t-left" - [decimal]="decimal" [disabled]="computedDisabled" [max]="value[1]" [min]="min" - [precision]="precision" [readOnly]="readOnly" + [tuiNumberFormat]="{precision}" [tuiTextfieldPostfix]="pluralize ? (value[0] | i18nPlural: pluralize) : ''" [(ngModel)]="leftTextfieldValue" (focusedChange)="onTextInputFocused($event)" @@ -41,12 +40,11 @@ automation-id="tui-input-range__right-input" tuiTextfieldAppearance="none" class="t-right" - [decimal]="decimal" [disabled]="computedDisabled" [max]="max" [min]="value[0]" - [precision]="precision" [readOnly]="readOnly" + [tuiNumberFormat]="{precision}" [tuiTextfieldPostfix]="pluralize ? (value[1] | i18nPlural: pluralize) : ''" [(ngModel)]="rightTextfieldValue" (focusedChange)="onTextInputFocused($event)" diff --git a/projects/kit/components/input-slider/input-slider.component.ts b/projects/kit/components/input-slider/input-slider.component.ts index 45abc4018d64..ce7774af7d64 100644 --- a/projects/kit/components/input-slider/input-slider.component.ts +++ b/projects/kit/components/input-slider/input-slider.component.ts @@ -20,7 +20,7 @@ import { tuiPure, tuiRound, } from '@taiga-ui/cdk'; -import type {TuiDecimal, TuiWithOptionalMinMax} from '@taiga-ui/core'; +import type {TuiWithOptionalMinMax} from '@taiga-ui/core'; import { TEXTFIELD_CONTROLLER_PROVIDER, TUI_TEXTFIELD_WATCHED_CONTROLLER, @@ -120,10 +120,6 @@ export class TuiInputSliderComponent return tuiGetFractionPartPadded(this.quantum).length; } - protected get decimal(): TuiDecimal { - return this.precision ? 'not-zero' : 'never'; - } - protected get showValueContent(): boolean { return Boolean(this.valueContent && !this.focused); } diff --git a/projects/kit/components/input-slider/input-slider.module.ts b/projects/kit/components/input-slider/input-slider.module.ts index 6fee92c520a0..5a0912fb9a2a 100644 --- a/projects/kit/components/input-slider/input-slider.module.ts +++ b/projects/kit/components/input-slider/input-slider.module.ts @@ -2,7 +2,7 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule} from '@angular/forms'; import {TuiFocusableModule} from '@taiga-ui/cdk'; -import {TuiTextfieldControllerModule} from '@taiga-ui/core'; +import {TuiNumberFormatModule, TuiTextfieldControllerModule} from '@taiga-ui/core'; import {TuiInputNumberModule} from '@taiga-ui/kit/components/input-number'; import {TuiSliderModule} from '@taiga-ui/kit/components/slider'; import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus'; @@ -16,6 +16,7 @@ import {TuiInputSliderComponent} from './input-slider.component'; PolymorpheusModule, TuiFocusableModule, TuiInputNumberModule, + TuiNumberFormatModule, TuiSliderModule, TuiTextfieldControllerModule, ], diff --git a/projects/kit/components/input-slider/input-slider.template.html b/projects/kit/components/input-slider/input-slider.template.html index 961dbc0eebfb..bfe7e1c88d0a 100644 --- a/projects/kit/components/input-slider/input-slider.template.html +++ b/projects/kit/components/input-slider/input-slider.template.html @@ -1,14 +1,13 @@