From b7795f728b062e81d90e154d8a445bb4df7acb30 Mon Sep 17 00:00:00 2001 From: Barsukov Nikita Date: Fri, 1 Apr 2022 10:53:50 +0300 Subject: [PATCH] feat(kit): `InputRange` refactor (use `InputNumber` inside) --- .../cypress/support/shared.entities.ts | 1 + .../tests/kit/input-range/input-range.spec.ts | 177 +++++++++ .../input-range/input-range.component.ts | 24 +- .../input-range/input-range.module.ts | 7 +- .../input-range/input-range.template.html | 203 ++++++++--- projects/kit/abstract/input-slider.ts | 90 ++--- .../input-number/input-number.style.less | 4 + .../input-number/input-number.template.html | 1 + .../input-range/input-range.component.ts | 341 +++++++++--------- .../input-range/input-range.module.ts | 40 +- .../input-range/input-range.style.less | 144 ++------ .../input-range/input-range.template.html | 162 +++++---- .../test/input-range.component.spec.ts | 162 ++++++--- .../input-slider/input-slider.component.ts | 12 - .../src/utils/native-input.page-object.ts | 7 +- 15 files changed, 795 insertions(+), 580 deletions(-) create mode 100644 projects/demo-integrations/cypress/tests/kit/input-range/input-range.spec.ts diff --git a/projects/demo-integrations/cypress/support/shared.entities.ts b/projects/demo-integrations/cypress/support/shared.entities.ts index 0d6c155fda748..6a6160f6a7760 100644 --- a/projects/demo-integrations/cypress/support/shared.entities.ts +++ b/projects/demo-integrations/cypress/support/shared.entities.ts @@ -8,6 +8,7 @@ export const EDITOR_PAGE_URL = 'components/editor-new'; export const MULTI_SELECT_PAGE_URL = 'components/multi-select'; export const SELECT_PAGE_URL = 'components/select'; export const SLIDER_PAGE_URL = 'components/slider'; +export const INPUT_RANGE_PAGE_URL = 'components/input-range'; export const INPUT_SLIDER_PAGE_URL = 'components/input-slider'; export const INPUT_PAGE_URL = 'components/input'; export const RANGE_PAGE_URL = 'components/range'; diff --git a/projects/demo-integrations/cypress/tests/kit/input-range/input-range.spec.ts b/projects/demo-integrations/cypress/tests/kit/input-range/input-range.spec.ts new file mode 100644 index 0000000000000..6db7755006427 --- /dev/null +++ b/projects/demo-integrations/cypress/tests/kit/input-range/input-range.spec.ts @@ -0,0 +1,177 @@ +import {INPUT_RANGE_PAGE_URL} from '../../../support/shared.entities'; + +describe('InputRange', () => { + beforeEach(() => { + cy.viewport('macbook-13'); + }); + + describe('Keyboard interactions', () => { + beforeEach(() => { + cy.tuiVisit(`${INPUT_RANGE_PAGE_URL}/API?min=-100&max=100&quantum=5`); + initializeAliases('#demoContent tui-input-range', [0, 10]); + }); + + it('pressing Arrow Down decreases LEFT value when LEFT text input is focused', () => { + cy.get('@leftTextInput').focus(); + + cy.get('body').type('{downarrow}'); + + cy.get('@leftSlider').should('have.value', -5); + cy.get('@leftTextInput').should('have.value', -5); + + cy.get('body').type('{downarrow}'); + + cy.get('@leftSlider').should('have.value', -10); + cy.get('@leftTextInput').should('have.value', -10); + }); + + it('pressing Arrow Down decreases RIGHT value when RIGHT text input is focused', () => { + cy.get('@rightTextInput').focus(); + + cy.get('body').type('{downarrow}'); + + cy.get('@rightSlider').should('have.value', 5); + cy.get('@rightTextInput').should('have.value', 5); + + cy.get('body').type('{downarrow}'); + + cy.get('@rightSlider').should('have.value', 0); + cy.get('@rightTextInput').should('have.value', 0); + }); + + it('pressing Arrow Up increases LEFT value when LEFT text input is focused', () => { + cy.get('@leftTextInput').focus(); + + cy.get('body').type('{uparrow}'); + + cy.get('@leftSlider').should('have.value', 5); + cy.get('@leftTextInput').should('have.value', 5); + + cy.get('body').type('{uparrow}'); + + cy.get('@leftSlider').should('have.value', 10); + cy.get('@leftTextInput').should('have.value', 10); + }); + + it('pressing Arrow Up increases RIGHT value when RIGHT text input is focused', () => { + cy.get('@rightTextInput').focus(); + + cy.get('body').type('{uparrow}'); + + cy.get('@rightSlider').should('have.value', 15); + cy.get('@rightTextInput').should('have.value', 15); + + cy.get('body').type('{uparrow}'); + + cy.get('@rightSlider').should('have.value', 20); + cy.get('@rightTextInput').should('have.value', 20); + }); + + it('cannot set right value less than left value via ArrowDown', () => { + cy.get('@rightTextInput').focus(); + + cy.get('body').type('{downarrow}{downarrow}'); + cy.get('body').type('{downarrow}{downarrow}'); + cy.get('body').type('{downarrow}{downarrow}'); + + cy.get('@leftSlider').should('have.value', 0); + cy.get('@leftTextInput').should('have.value', 0); + cy.get('@rightSlider').should('have.value', 0); + cy.get('@rightTextInput').should('have.value', 0); + }); + + it('cannot set left value more than right value via ArrowUp', () => { + cy.get('@leftTextInput').focus(); + + cy.get('body').type('{uparrow}{uparrow}'); + cy.get('body').type('{uparrow}{uparrow}'); + cy.get('body').type('{uparrow}{uparrow}'); + + cy.get('@leftSlider').should('have.value', 10); + cy.get('@leftTextInput').should('have.value', 10); + cy.get('@rightSlider').should('have.value', 10); + cy.get('@rightTextInput').should('have.value', 10); + }); + + it('pressing ArrowRight does not change any value (this key is for caret navigation only)', () => { + cy.get('@leftTextInput').focus(); + cy.get('body').type('{rightarrow}{rightarrow}'); + + cy.get('@rightTextInput').focus(); + cy.get('body').type('{rightarrow}{rightarrow}'); + + cy.get('@leftSlider').should('have.value', 0); + cy.get('@leftTextInput').should('have.value', 0); + cy.get('@rightSlider').should('have.value', 10); + cy.get('@rightTextInput').should('have.value', 10); + }); + + it('pressing ArrowLeft does not change any value (this key is for caret navigation only)', () => { + cy.get('@leftTextInput').focus(); + cy.get('body').type('{leftarrow}{leftarrow}'); + + cy.get('@rightTextInput').focus(); + cy.get('body').type('{leftarrow}{leftarrow}'); + + cy.get('@leftSlider').should('have.value', 0); + cy.get('@leftTextInput').should('have.value', 0); + cy.get('@rightSlider').should('have.value', 10); + cy.get('@rightTextInput').should('have.value', 10); + }); + }); + + describe('Rounding numbers (to the nearest step which satisfies quantum) (min=0 | max=10 | quantum=2.5)', () => { + beforeEach(() => { + cy.tuiVisit(`${INPUT_RANGE_PAGE_URL}/API?min=0&max=10&quantum=2.5`); + initializeAliases('#demoContent tui-input-range', [0, 10]); + }); + + const testsConditions = [ + {typedValue: '9', expectedRoundedValue: '10'}, + {typedValue: '8', expectedRoundedValue: '7,5'}, + {typedValue: '7,6', expectedRoundedValue: '7,5'}, + {typedValue: '7.4', expectedRoundedValue: '7,5'}, + {typedValue: '7', expectedRoundedValue: '7,5'}, + {typedValue: '6', expectedRoundedValue: '5'}, + {typedValue: '3.2', expectedRoundedValue: '2,5'}, + {typedValue: '1', expectedRoundedValue: '0'}, + {typedValue: '0.1', expectedRoundedValue: '0'}, + ] as const; + + for (const {typedValue, expectedRoundedValue} of testsConditions) { + it(`${typedValue} => ${expectedRoundedValue}`, () => { + cy.get('@rightTextInput') + .focus() + .clear() + .type(typedValue) + .blur() + .should('have.value', expectedRoundedValue); + }); + } + }); +}); + +function initializeAliases( + inputRangeSelector: string, + [expectedLeftValue, expectedRightValue]: [number, number], +) { + cy.get(`${inputRangeSelector} tui-input-number:first-of-type input`) + .should('be.visible') + .should('have.value', expectedLeftValue) + .as('leftTextInput'); + + cy.get(`${inputRangeSelector} tui-input-number:last-of-type input`) + .should('be.visible') + .should('have.value', expectedRightValue) + .as('rightTextInput'); + + cy.get(`${inputRangeSelector} tui-range [tuiSlider]:first-of-type`) + .should('exist') + .should('have.value', expectedLeftValue) + .as('leftSlider'); + + cy.get(`${inputRangeSelector} tui-range [tuiSlider]:last-of-type`) + .should('be.visible') + .should('have.value', expectedRightValue) + .as('rightSlider'); +} diff --git a/projects/demo/src/modules/components/input-range/input-range.component.ts b/projects/demo/src/modules/components/input-range/input-range.component.ts index e67bd9ad5313a..5dace2068afdb 100644 --- a/projects/demo/src/modules/components/input-range/input-range.component.ts +++ b/projects/demo/src/modules/components/input-range/input-range.component.ts @@ -2,6 +2,7 @@ import {Component, forwardRef} from '@angular/core'; import {FormControl} from '@angular/forms'; import {changeDetection} from '@demo/emulate/change-detection'; import {TuiDocExample} from '@taiga-ui/addon-doc'; +import {TuiContextWithImplicit} from '@taiga-ui/cdk'; import {TuiPluralize, TuiSizeL} from '@taiga-ui/core'; import {TuiKeySteps} from '@taiga-ui/kit'; @@ -35,7 +36,7 @@ export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { LESS: import('!!raw-loader!./examples/2/index.less'), }; - control = new FormControl(); + control = new FormControl([0, 10]); minVariants: readonly number[] = [0, 5, 7.77, -10]; @@ -45,13 +46,9 @@ export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { max = this.maxVariants[0]; - segmentsVariants: readonly number[] = [0, 1, 5, 13]; + segments = 0; - segments = this.segmentsVariants[0]; - - stepsVariants: readonly number[] = [0, 4, 10]; - - steps = this.stepsVariants[0]; + steps = 0; quantumVariants: readonly number[] = [1, 0.001, 10, 100]; @@ -85,4 +82,17 @@ export class ExampleTuiInputRangeComponent extends AbstractExampleTuiControl { keyStepsVariants: readonly TuiKeySteps[] = [[[50, 1000]]]; keySteps = null; + + readonly valueContentVariants = [ + '', + 'TOP SECRET', + ({$implicit: val}: TuiContextWithImplicit) => + val === this.max ? 'MAX' : val, + ({$implicit: val}: TuiContextWithImplicit) => + val === this.min ? 'MIN' : val, + ({$implicit: val}: TuiContextWithImplicit) => (val === 5 ? 'FIVE' : val), + ]; + + leftValueContent = this.valueContentVariants[0]; + rightValueContent = this.valueContentVariants[0]; } 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 40c8804ebe0d6..54544c1b7bd14 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 @@ -3,7 +3,11 @@ import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {RouterModule} from '@angular/router'; import {generateRoutes, TuiAddonDocModule} from '@taiga-ui/addon-doc'; -import {TuiButtonModule, TuiLinkModule} from '@taiga-ui/core'; +import { + TuiButtonModule, + TuiLinkModule, + TuiTextfieldControllerModule, +} from '@taiga-ui/core'; import { TuiInputRangeModule, TuiInputSliderModule, @@ -27,6 +31,7 @@ import {ExampleTuiInputRangeComponent} from './input-range.component'; TuiAddonDocModule, TuiButtonModule, TuiLinkModule, + TuiTextfieldControllerModule, RouterModule.forChild(generateRoutes(ExampleTuiInputRangeComponent)), ], declarations: [ 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 ea49f4b8f240b..36a6611b8c4a5 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 @@ -39,20 +39,24 @@ Range @@ -69,6 +73,26 @@ formControl.disable() ) + + Min value + + + Max value + - Min value + Number of actual discrete slider steps - Max value + A number of visual segments - Label for min value + Anchor points of non-uniform format between value and position - Label for max value + A template for custom view of the left selected value. + + + A template for custom view of the right selected value. - A number of visual segments + Component is read only + + + Size + +

+ Use + tuiTextfieldSize + instead. +

+
+ + Label for min value + +

+ Use + leftValueContent + instead. +

+
+ + Label for max value + +

+ Use + rightValueContent + instead. +

Plural forms for segments + +

+ + See examples how to create ticks without this property + (outside of the component). + +

- + +
+ Can be expanded with + - Size - + TuiTextfieldController + +
+ +

+ Requires you to import + TuiTextfieldControllerModule +

+ + - Number of actual discrete slider steps + Label is outside a component and made with + + Label + + - Anchor points of non-uniform format between value and position + Size -
diff --git a/projects/kit/abstract/input-slider.ts b/projects/kit/abstract/input-slider.ts index 7392fae78e506..3116e096bf0a6 100644 --- a/projects/kit/abstract/input-slider.ts +++ b/projects/kit/abstract/input-slider.ts @@ -1,29 +1,13 @@ import {Directive, HostBinding, Input} from '@angular/core'; +import {AbstractTuiControl, clamp, round, tuiDefaultProp, tuiPure} from '@taiga-ui/cdk'; import { - AbstractTuiControl, - clamp, - round, - tuiDefaultProp, - TuiInputModeT, - TuiMapper, - tuiPure, -} from '@taiga-ui/cdk'; -import { - maskedNumberStringToNumber, - NumberFormatSettings, - tuiCreateAutoCorrectedNumberPipe, - tuiCreateNumberMask, TuiPluralize, tuiPluralizeToICU, TuiSizeL, - TuiTextMaskOptions, TuiWithOptionalMinMax, } from '@taiga-ui/core'; -import {tuiEnableAutoCorrectDecimalSymbol} from '@taiga-ui/core/utils'; import {TUI_FLOATING_PRECISION} from '@taiga-ui/kit/constants'; import {TuiKeySteps} from '@taiga-ui/kit/types'; -import {getPrecision} from '@taiga-ui/kit/utils'; -import {TextMaskConfig} from 'angular2-text-mask'; export function quantumAssertion(quantum: number): boolean { return quantum > 0; @@ -38,8 +22,6 @@ export abstract class AbstractTuiInputSlider extends AbstractTuiControl implements TuiWithOptionalMinMax { - protected abstract readonly numberFormat: NumberFormatSettings; - @Input() @tuiDefaultProp() min = 0; @@ -48,10 +30,28 @@ export abstract class AbstractTuiInputSlider @tuiDefaultProp() max = Infinity; + /** + * @deprecated This input-property will be deleted in next major update. + * Use `valueContent` for `InputSlider`. + * Use `leftValueContent` for `InputRange`. + * ___ + * TODO remove in v3.0. + * Dont forget to delete backward-compatibility helpers inside `InputSlider` and `InputRange`: + *** {@link legacyMinMaxLabel} + */ @Input() @tuiDefaultProp() minLabel = ''; + /** + * @deprecated This input-property will be deleted in next major update. + * Use `valueContent` for `InputSlider`. + * Use `rightValueContent` for `InputRange`. + * ___ + * TODO remove in v3.0. + * Dont forget to delete backward-compatibility helpers inside `InputSlider` and `InputRange`: + *** {@link legacyMinMaxLabel} + */ @Input() @tuiDefaultProp() maxLabel = ''; @@ -101,8 +101,13 @@ export abstract class AbstractTuiInputSlider @tuiDefaultProp() keySteps: TuiKeySteps | null = null; + /** + * @deprecated use `tuiTextfieldSize` instead + * TODO delete in v3.0 + */ @Input() @HostBinding('attr.data-size') + @tuiDefaultProp() size: TuiSizeL = 'l'; pluralizeMap: Record | null = null; @@ -126,41 +131,11 @@ export abstract class AbstractTuiInputSlider return segment === 0 ? `${texts[0]}` : `${texts[1]}`; } - mask: TuiMapper = (quantum: number, min: number) => - ({ - mask: tuiCreateNumberMask({ - allowNegative: min < 0, - allowDecimal: !Number.isInteger(quantum), - decimalSymbol: this.numberFormat.decimalSeparator, - thousandSymbol: this.numberFormat.thousandSeparator, - decimalLimit: getPrecision(quantum), - autoCorrectDecimalSymbol: tuiEnableAutoCorrectDecimalSymbol( - this.numberFormat, - ), - }), - pipe: tuiCreateAutoCorrectedNumberPipe( - 0, - this.numberFormat.decimalSeparator, - this.numberFormat.thousandSeparator, - undefined, - min < 0, - ), - guide: false, - } as TuiTextMaskOptions as unknown as TextMaskConfig); - @HostBinding('class._segmented') get segmented(): boolean { return this.segments > 0; } - get hasPlaceholder(): boolean { - return this.size === 'l'; - } - - get inputMode(): TuiInputModeT { - return Number.isInteger(this.quantum) ? 'numeric' : 'decimal'; - } - get length(): number { return this.max - this.min; } @@ -194,23 +169,6 @@ export abstract class AbstractTuiInputSlider : clamp(value, this.min, this.max); } - protected capInputValue(value: string, max: number = this.max): number | null { - const capped = Math.min( - maskedNumberStringToNumber( - value, - this.numberFormat.decimalSeparator, - this.numberFormat.thousandSeparator, - ), - max, - ); - - if (this.min < 0 && capped < this.min) { - return this.min; - } - - return isNaN(capped) || capped < this.min ? null : capped; - } - @tuiPure private computePureKeySteps( keySteps: TuiKeySteps | null, diff --git a/projects/kit/components/input-number/input-number.style.less b/projects/kit/components/input-number/input-number.style.less index 2a1232638bc5e..7270e255aede5 100644 --- a/projects/kit/components/input-number/input-number.style.less +++ b/projects/kit/components/input-number/input-number.style.less @@ -8,3 +8,7 @@ border-radius: inherit; text-align: inherit; } + +.t-value-content { + width: 100%; +} diff --git a/projects/kit/components/input-number/input-number.template.html b/projects/kit/components/input-number/input-number.template.html index c835a49fdf2ec..ff026844bb537 100644 --- a/projects/kit/components/input-number/input-number.template.html +++ b/projects/kit/components/input-number/input-number.template.html @@ -28,6 +28,7 @@
diff --git a/projects/kit/components/input-range/input-range.component.ts b/projects/kit/components/input-range/input-range.component.ts index ac779cc1fcd2a..345f4ccfde576 100644 --- a/projects/kit/components/input-range/input-range.component.ts +++ b/projects/kit/components/input-range/input-range.component.ts @@ -2,35 +2,55 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + Directive, ElementRef, forwardRef, HostBinding, Inject, + Input, Optional, + QueryList, Self, ViewChild, + ViewChildren, } from '@angular/core'; import {NgControl} from '@angular/forms'; import { + EMPTY_QUERY, isNativeFocused, + isNativeFocusedIn, setNativeFocused, TUI_FOCUSABLE_ITEM_ACCESSOR, TUI_IS_MOBILE, + TuiContextWithImplicit, + tuiDefaultProp, TuiFocusableElementAccessor, TuiNativeFocusableElement, - tuiPure, } from '@taiga-ui/cdk'; import { - formatNumber, - maskedMoneyValueIsEmpty, - maskedNumberStringToNumber, - NumberFormatSettings, - TUI_NUMBER_FORMAT, + getFractionPartPadded, + TEXTFIELD_CONTROLLER_PROVIDER, TUI_TEXTFIELD_APPEARANCE, - TuiBrightness, - TuiModeDirective, + TUI_TEXTFIELD_WATCHED_CONTROLLER, + TuiDecimalT, + TuiSizeL, + TuiTextfieldController, } from '@taiga-ui/core'; -import {AbstractTuiInputSlider} from '@taiga-ui/kit/abstract'; +import {AbstractTuiInputSlider, quantumAssertion} from '@taiga-ui/kit/abstract'; +import {TuiInputNumberComponent} from '@taiga-ui/kit/components/input-number'; +import {TuiRangeComponent} from '@taiga-ui/kit/components/range'; +import {TuiKeySteps} from '@taiga-ui/kit/types'; +import {PolymorpheusContent} from '@tinkoff/ng-polymorpheus'; + +/** + * Turn on new `InputRange`'s version. + * The new version will behave almost the same as `InputRange` from the next major release. + * @deprecated TODO remove me in v3.0 and make `InputRange` always "new". + */ +@Directive({ + selector: 'tui-input-range[new]', +}) +export class TuiNewInputRangeDirective {} // @dynamic @Component({ @@ -43,17 +63,53 @@ import {AbstractTuiInputSlider} from '@taiga-ui/kit/abstract'; provide: TUI_FOCUSABLE_ITEM_ACCESSOR, useExisting: forwardRef(() => TuiInputRangeComponent), }, + TEXTFIELD_CONTROLLER_PROVIDER, ], }) export class TuiInputRangeComponent extends AbstractTuiInputSlider<[number, number]> implements TuiFocusableElementAccessor { - @ViewChild('nativeLeft') - private readonly nativeLeft?: ElementRef; + @ViewChildren(TuiInputNumberComponent) + private readonly inputNumberRefs: QueryList = EMPTY_QUERY; + + @ViewChild(TuiRangeComponent) + private readonly rangeRef: TuiRangeComponent | null = null; + + private lastActiveSide: 'left' | 'right' = 'left'; + + @Input() + @tuiDefaultProp() + min = 0; + + /* TODO: make `100` as default value (like in native sliders) */ + @Input() + @tuiDefaultProp() + max = Infinity; + + @Input() + @tuiDefaultProp(quantumAssertion, 'Quantum must be positive') + quantum = 1; + + @Input() + @tuiDefaultProp() + steps = 0; + + @Input() + @tuiDefaultProp() + segments = 0; + + @Input() + @tuiDefaultProp() + keySteps: TuiKeySteps | null = null; + + @Input() + @tuiDefaultProp() + leftValueContent: PolymorpheusContent> = ''; - @ViewChild('nativeRight') - private readonly nativeRight?: ElementRef; + @Input() + @tuiDefaultProp() + rightValueContent: PolymorpheusContent> = ''; constructor( @Optional() @@ -61,212 +117,147 @@ export class TuiInputRangeComponent @Inject(NgControl) control: NgControl | null, @Inject(ChangeDetectorRef) changeDetectorRef: ChangeDetectorRef, - @Optional() - @Inject(TuiModeDirective) - protected readonly modeDirective: TuiModeDirective | null, @Inject(TUI_IS_MOBILE) private readonly isMobile: boolean, - @Inject(TUI_NUMBER_FORMAT) - protected readonly numberFormat: NumberFormatSettings, @Inject(TUI_TEXTFIELD_APPEARANCE) readonly appearance: string, + @Inject(ElementRef) private readonly elementRef: ElementRef, + @Inject(TUI_TEXTFIELD_WATCHED_CONTROLLER) + readonly controller: TuiTextfieldController, + @Optional() + @Inject(TuiNewInputRangeDirective) + readonly isNew: TuiNewInputRangeDirective | null, ) { super(control, changeDetectorRef); } - get nativeFocusableElement(): TuiNativeFocusableElement | null { - return !this.nativeLeft || this.disabled ? null : this.nativeLeft.nativeElement; + get leftFocusableElement(): HTMLInputElement | null { + const [leftTextInputRef] = this.inputNumberRefs; + + return leftTextInputRef?.nativeFocusableElement || null; } - get focused(): boolean { - return this.focusedLeft || this.focusedRight; + get rightFocusableElement(): HTMLInputElement | null { + const [, rightTextInputRef] = this.inputNumberRefs; + + return rightTextInputRef?.nativeFocusableElement || null; } - get focusedLeft(): boolean { - return !!this.nativeLeft && isNativeFocused(this.nativeLeft.nativeElement); + get nativeFocusableElement(): TuiNativeFocusableElement | null { + return !this.leftFocusableElement || this.disabled + ? null + : this.leftFocusableElement; } - get focusedRight(): boolean { - return !!this.nativeRight && isNativeFocused(this.nativeRight.nativeElement); + get focused(): boolean { + return isNativeFocusedIn(this.elementRef.nativeElement); } - @HostBinding('class._min-label') - get showMinLabel(): boolean { - return !this.focusedLeft && !!this.minLabel && this.value[0] === this.min; + get showLeftValueContent(): boolean { + return ( + !isNativeFocused(this.leftFocusableElement) && + !(this.rangeRef?.focused && this.lastActiveSide === 'left') + ); } - @HostBinding('class._max-label') - get showMaxLabel(): boolean { - return !this.focusedRight && !!this.maxLabel && this.value[1] === this.max; + get showRightValueContent(): boolean { + return ( + !isNativeFocused(this.rightFocusableElement) && + !(this.rangeRef?.focused && this.lastActiveSide === 'right') + ); } - @HostBinding('attr.data-mode') - get hostMode(): TuiBrightness | null { - return this.modeDirective && this.modeDirective.mode; + get precision(): number { + return getFractionPartPadded(this.quantum).length; } - get inputValueLeft(): string { - return this.nativeLeft ? this.nativeLeft.nativeElement.value : ''; + get decimal(): TuiDecimalT { + return this.precision ? 'not-zero' : 'never'; } - get inputValueRight(): string { - return this.nativeRight ? this.nativeRight.nativeElement.value : ''; + get computedSteps(): number { + return this.steps || (this.max - this.min) / this.quantum; } - get computedValueLeft(): string { - return this.computedPureValueLeft(this.value[0]); + get computedSize(): TuiSizeL { + return this.isNew && this.controller.size !== 's' + ? this.controller.size + : this.size; } - get computedValueRight(): string { - return this.computedPureValueRight(this.value[1]); + /** + * TODO keep only controller.labelOutside in v3.0 (let user configure this property by yourself) + */ + @HostBinding('class._label-outside') + get legacyLabelOutside(): boolean { + return this.isNew ? this.controller.labelOutside : this.computedSize === 'm'; } onActiveZone(active: boolean) { this.updateFocused(active); } - onMouseDown() { - if (this.nativeRight && !this.isMobile) { - setNativeFocused(this.nativeRight.nativeElement); - } - } - - onKeyDownArrowUpLeft(event: KeyboardEvent) { - if (this.readOnly) { + onTextInputFocused(focused: boolean, right: boolean) { + if (focused) { return; } - event.preventDefault(); - this.processStep(true, false); - } + const [leftTextInputRef, rightTextInputRef] = this.inputNumberRefs; + const inputRef = right ? rightTextInputRef : leftTextInputRef; + const valueIndex = right ? 1 : 0; - onKeyDownArrowDownLeft(event: KeyboardEvent) { - if (this.readOnly) { - return; + if (!inputRef.nativeValue || inputRef.value !== this.value[valueIndex]) { + this.updateTextInputValue(this.safeCurrentValue[valueIndex], right); } - - event.preventDefault(); - this.processStep(false, false); } - onKeyDownArrowUpRight(event: KeyboardEvent) { + incrementByStep(event: KeyboardEvent, right: boolean) { if (this.readOnly) { return; } event.preventDefault(); - this.processStep(true, true); + this.processStep(true, right); } - onKeyDownArrowDownRight(event: KeyboardEvent) { + decrementByStep(event: KeyboardEvent, right: boolean) { if (this.readOnly) { return; } event.preventDefault(); - this.processStep(false, true); + this.processStep(false, right); } - onInputLeft() { - const value = this.inputValueLeft; - const capped = this.capInputValue(value, this.value[1]); - const postfix = value.slice(-1)[0] === ',' ? ',' : ''; - - if (maskedMoneyValueIsEmpty(value) || capped === null) { - return; - } - - const newValue = this.formatNumber(capped) + postfix; - - if (this.nativeLeft && this.inputValueLeft !== newValue) { - this.nativeLeft.nativeElement.value = newValue; - } - - this.updateValue([capped, this.value[1]]); + onInputLeft(value: number | null) { + this.safelyUpdateValue([value ?? this.safeCurrentValue[0], this.value[1]]); } - onInputRight() { - const value = this.inputValueRight; - const capped = this.capInputValue(value); - const postfix = value.slice(-1)[0] === ',' ? ',' : ''; - - if (maskedMoneyValueIsEmpty(value) || capped === null) { - return; - } - - const newValue = this.formatNumber(capped) + postfix; - - if (this.nativeRight && this.inputValueRight !== newValue) { - this.nativeRight.nativeElement.value = newValue; - } - - if (capped >= this.value[0]) { - this.updateValue([this.value[0], capped]); - } + onInputRight(value: number | null) { + this.safelyUpdateValue([this.value[0], value ?? this.safeCurrentValue[1]]); } - onRangeValue(value: [number, number]) { - const guardedValue = value.map(item => this.valueGuard(item)) as [number, number]; + onRangeValue([left, right]: [number, number]) { + this.rangeRef?.nativeFocusableElement?.focus(); - if ( - !this.nativeLeft || - !this.nativeRight || - (guardedValue[0] === this.value[0] && guardedValue[1] === this.value[1]) - ) { - return; - } + const isLeftValueChanged = left !== this.value[0]; + const isRightValueChanged = right !== this.value[1]; - if (!this.isMobile) { - const element = - guardedValue[0] !== this.value[0] - ? this.nativeLeft.nativeElement - : this.nativeRight.nativeElement; - - setNativeFocused(element); + if (isLeftValueChanged || isRightValueChanged) { + this.lastActiveSide = isLeftValueChanged ? 'left' : 'right'; } - this.updateValue(guardedValue); - this.nativeLeft.nativeElement.value = this.formatNumber(guardedValue[0]); + this.safelyUpdateValue([left, right]); } - onLeftFocused(focused: boolean) { - if (focused || !this.nativeLeft) { - return; - } - - const inputValue = maskedNumberStringToNumber( - this.computedValueLeft, - this.numberFormat.decimalSeparator, - this.numberFormat.thousandSeparator, - ); - const value = isNaN(inputValue) ? this.min : this.valueGuard(inputValue); - - this.nativeLeft.nativeElement.value = this.formatNumber(value); + focusToTextInput() { + const element = + this.lastActiveSide === 'left' + ? this.leftFocusableElement + : this.rightFocusableElement; - if (value !== this.value[0]) { - this.updateValue([value, this.value[1]]); - } - } - - onRightFocused(focused: boolean) { - if (focused || !this.nativeRight) { - return; - } - - const inputValue = maskedNumberStringToNumber( - this.computedValueRight, - this.numberFormat.decimalSeparator, - this.numberFormat.thousandSeparator, - ); - - const value = isNaN(inputValue) - ? this.value[0] - : this.valueGuard(Math.max(inputValue, this.value[0])); - - this.nativeRight.nativeElement.value = this.formatNumber(value); - - if (value !== this.value[1]) { - this.updateValue([this.value[0], value]); + if (!this.isMobile && element) { + setNativeFocused(element); } } @@ -274,23 +265,14 @@ export class TuiInputRangeComponent return [0, 0]; } - @tuiPure - private computedPureValueLeft(value: number) { - return this.formatNumber(value); - } + private safelyUpdateValue([leftValue, rightValue]: [number, number]) { + const leftGuardedValue = this.valueGuard(leftValue); + const rightGuardedValue = this.valueGuard(rightValue); - @tuiPure - private computedPureValueRight(value: number) { - return this.formatNumber(value); - } + const leftSafeValue = Math.min(leftGuardedValue, rightGuardedValue); + const rightSafeValue = Math.max(leftGuardedValue, rightGuardedValue); - private formatNumber(value: number): string { - return formatNumber( - value, - null, - this.numberFormat.decimalSeparator, - this.numberFormat.thousandSeparator, - ); + this.updateValue([leftSafeValue, rightSafeValue]); } private processStep(increment: boolean, right: boolean) { @@ -306,7 +288,28 @@ export class TuiInputRangeComponent ]; if (value[0] !== this.value[0] || value[1] !== this.value[1]) { - this.updateValue(value); + this.safelyUpdateValue(value); + this.updateTextInputValue(right ? value[1] : value[0], right); + } + } + + private updateTextInputValue(value: number, right: boolean) { + const [leftInputRef, rightInputRef] = this.inputNumberRefs; + const textInputRef = right ? rightInputRef : leftInputRef; + + if (textInputRef) { + textInputRef.nativeValue = textInputRef.getFormattedValue(value); } } } + +@Directive({ + selector: '[tuiTextfieldNoneAppearance]', + providers: [ + { + provide: TUI_TEXTFIELD_APPEARANCE, + useValue: 'none', // Not existing appearance to prevent any customization + }, + ], +}) +export class TuiTextfieldNoneAppearanceDirective {} diff --git a/projects/kit/components/input-range/input-range.module.ts b/projects/kit/components/input-range/input-range.module.ts index 92a8b817581af..24c1d8e727d1c 100644 --- a/projects/kit/components/input-range/input-range.module.ts +++ b/projects/kit/components/input-range/input-range.module.ts @@ -1,38 +1,36 @@ import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {FormsModule, ReactiveFormsModule} from '@angular/forms'; -import { - TuiActiveZoneModule, - TuiFocusableModule, - TuiFocusedModule, - TuiHoveredModule, - TuiInputModeModule, - TuiMapperPipeModule, - TuiPressedModule, -} from '@taiga-ui/cdk'; -import {TuiWrapperModule} from '@taiga-ui/core'; +import {TuiActiveZoneModule, TuiPressedModule} from '@taiga-ui/cdk'; +import {TuiTextfieldControllerModule, TuiWrapperModule} from '@taiga-ui/core'; +import {TuiInputNumberModule} from '@taiga-ui/kit/components/input-number'; import {TuiRangeModule} from '@taiga-ui/kit/components/range'; -import {TextMaskModule} from 'angular2-text-mask'; +import {PolymorpheusModule} from '@tinkoff/ng-polymorpheus'; -import {TuiInputRangeComponent} from './input-range.component'; +import { + TuiInputRangeComponent, + TuiNewInputRangeDirective, + TuiTextfieldNoneAppearanceDirective, +} from './input-range.component'; @NgModule({ imports: [ CommonModule, FormsModule, ReactiveFormsModule, - TextMaskModule, - TuiFocusableModule, - TuiFocusedModule, - TuiHoveredModule, - TuiPressedModule, - TuiMapperPipeModule, - TuiInputModeModule, + PolymorpheusModule, TuiActiveZoneModule, + TuiInputNumberModule, + TuiPressedModule, TuiRangeModule, + TuiTextfieldControllerModule, TuiWrapperModule, ], - declarations: [TuiInputRangeComponent], - exports: [TuiInputRangeComponent], + declarations: [ + TuiInputRangeComponent, + TuiTextfieldNoneAppearanceDirective, + TuiNewInputRangeDirective, + ], + exports: [TuiInputRangeComponent, TuiNewInputRangeDirective], }) export class TuiInputRangeModule {} diff --git a/projects/kit/components/input-range/input-range.style.less b/projects/kit/components/input-range/input-range.style.less index 9259958610171..722d97f334cc8 100644 --- a/projects/kit/components/input-range/input-range.style.less +++ b/projects/kit/components/input-range/input-range.style.less @@ -1,143 +1,52 @@ -@import 'taiga-ui-local'; - -@padding: 1rem; -@padding2: @padding * 2; - -:host { - .createStackingContext(); - display: block; - font: var(--tui-font-text-m); - border-radius: var(--tui-radius-m); - color: var(--tui-text-01); - - &._segmented { - // TODO: research if it can be used in rem units - /* stylelint-disable-next-line */ - border-bottom: 26px solid transparent; - } - - &[data-mode='onDark'] { - color: var(--tui-base-01); +tui-input-number ::ng-deep tui-wrapper { + &:after { + border: none; } } -.t-native-wrapper { - .fullsize(); +.t-wrapper { display: flex; } -.t-pluralize { - display: flex; - align-items: center; - padding-right: 0.75rem; - margin-left: -0.5rem; - - &_right { - margin-left: -0.75rem; - - :host[data-size='l'] & { - padding-top: 1.25rem; - } - - :host._disabled & { - color: var(--tui-text-03); - } - - :host[data-mode='onDark']._disabled & { - color: var(--tui-text-03-night); - } - } -} - -.t-native { - .clearinput(); +.t-text-input { flex: 1; - min-width: 0; - color: var(--tui-text-01); - box-sizing: border-box; - padding: 0 @padding; - outline: none; - &_right { + &:last-of-type { text-align: right; } - - &_hidden { - opacity: 0; - } - - :host._disabled & { - color: var(--tui-text-03); - user-select: none; - } - - :host[data-size='l'] & { - padding: 1.25rem @padding 0; - } - - :host[data-mode='onDark'] & { - color: var(--tui-text-01-night); - } - - :host[data-mode='onDark']._disabled & { - color: var(--tui-text-03-night); - } } -.t-content { +.t-pluralize-right { display: flex; - height: var(--tui-height-m); - padding: 0 @padding; - justify-content: space-between; align-items: center; + padding: 1.125rem var(--tui-padding-m) 0 0; + margin-left: -0.75rem; + font: var(--tui-font-text-s); :host[data-size='l'] & { - height: var(--tui-height-l); - padding: 0 @padding; - } - - :host[data-size='l']._disabled & { - color: var(--tui-text-03); + font: var(--tui-font-text-m); + padding-top: 1.25rem; + margin-left: -1rem; + padding-right: var(--tui-padding-l); } - :host[data-size='l'][data-mode='onDark']._disabled & { - color: var(--tui-text-03-night); + :host._label-outside & { + padding-top: 0; } -} - -.t-placeholder { - .textfield-placeholder(); - .fullsize(); - left: @padding; - line-height: var(--tui-height-l); -} - -.t-value { - visibility: hidden; - overflow: hidden; - padding-right: 0.75rem; :host._disabled & { color: var(--tui-text-03); } } -.t-label { - display: flex; - width: 50%; - - :host[data-size='l'] & { - padding-top: 1.25rem; - } -} - -.t-max { - text-align: right; - flex: 1; +:host { + display: block; + border-radius: var(--tui-radius-m); - :host[data-size='l'] & { - padding-top: 1.25rem; - line-height: calc(var(--tui-height-l) - 1.25rem); + &._segmented { + // TODO: delete it in v3.0 + /* stylelint-disable-next-line */ + border-bottom: 26px solid transparent; } } @@ -147,13 +56,6 @@ left: 0; right: 0; z-index: 1; - border-top-left-radius: 0; - border-top-right-radius: 0; margin: -0.125rem 0 0; background: transparent; - - :host._disabled &, - :host._readonly & { - pointer-events: none; - } } diff --git a/projects/kit/components/input-range/input-range.template.html b/projects/kit/components/input-range/input-range.template.html index 84ac97447d7f4..f35c973a5b175 100644 --- a/projects/kit/components/input-range/input-range.template.html +++ b/projects/kit/components/input-range/input-range.template.html @@ -1,4 +1,5 @@ - - -
- - {{ inputValueLeft }} - - {{ value[0] | i18nPlural: pluralizeMap }} - - - - {{ minLabel }} - - - {{ maxLabel }} - -
+
+ -
+
+ + + + - - - - {{ value[1] | i18nPlural: pluralizeMap }} - -
+  {{value[1] | i18nPlural: pluralizeMap || pluralizeMapFallback}} + +
+ + + + {{minLabel}} + + {{value}} {{value | i18nPlural: pluralizeMap || + pluralizeMapFallback}} + + + + + + {{maxLabel}} + + {{value}} {{value | i18nPlural: pluralizeMap || + pluralizeMapFallback}} + + diff --git a/projects/kit/components/input-range/test/input-range.component.spec.ts b/projects/kit/components/input-range/test/input-range.component.spec.ts index 64ef2eff2fb62..6e78300447f2a 100644 --- a/projects/kit/components/input-range/test/input-range.component.spec.ts +++ b/projects/kit/components/input-range/test/input-range.component.spec.ts @@ -1,6 +1,7 @@ -import {Component, ViewChild} from '@angular/core'; +import {Component, DebugElement, ViewChild} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FormControl, ReactiveFormsModule} from '@angular/forms'; +import {By} from '@angular/platform-browser'; import {CHAR_NO_BREAK_SPACE} from '@taiga-ui/cdk'; import {configureTestSuite, NativeInputPO, PageObject} from '@taiga-ui/testing'; @@ -48,18 +49,28 @@ describe('InputRange', () => { let fixture: ComponentFixture; let testComponent: TestComponent; let pageObject: PageObject; + + let leftInputWrapper: DebugElement; + let rightInputWrapper: DebugElement; + let inputPOLeft: NativeInputPO; let inputPORight: NativeInputPO; + const testContext = { get prefix() { return 'tui-input-range__'; }, + get nativeInputAutoId() { + return 'tui-primitive-textfield__native-input'; + }, + get valueContentAutoId() { + return 'tui-primitive-textfield__value'; + }, + get valueDecorationAutoId() { + return 'tui-primitive-textfield__value-decoration'; + }, }; - function aid(aid: string): HTMLElement & {textContent: string} { - return pageObject.getByAutomationId(aid)!.nativeElement; - } - configureTestSuite(() => { TestBed.configureTestingModule({ imports: [TuiInputRangeModule, ReactiveFormsModule], @@ -67,102 +78,76 @@ describe('InputRange', () => { }); }); - beforeEach(() => { + beforeEach(async () => { fixture = TestBed.createComponent(TestComponent); pageObject = new PageObject(fixture); testComponent = fixture.componentInstance; + fixture.detectChanges(); - inputPOLeft = new NativeInputPO(fixture, `${testContext.prefix}native-left`); - inputPORight = new NativeInputPO(fixture, `${testContext.prefix}native-right`); + await fixture.whenStable(); + + initializeInputsPO(); }); describe('Default values', () => { beforeEach(() => { testComponent.default = true; fixture.detectChanges(); + + initializeInputsPO(); }); it('minLabel is missing', () => { - expect( - pageObject.getByAutomationId(`${testContext.prefix}min-label`), - ).toBeNull(); + expect(getLeftValueContent()).toBeNull(); }); it('maxLabel is missing', () => { testComponent.control.setValue([0, 10]); fixture.detectChanges(); - expect( - pageObject.getByAutomationId(`${testContext.prefix}min-label`), - ).toBeNull(); + expect(getRightValueContent()).toBeNull(); }); it('Plural signature missing', () => { - expect( - pageObject.getByAutomationId(`${testContext.prefix}pluralize-left`), - ).toBeNull(); - expect( - pageObject.getByAutomationId(`${testContext.prefix}pluralize-right`), - ).toBeNull(); + expect(getLeftValueContent()).toBeNull(); + expect(getRightValueContent()).toBeNull(); }); }); describe('Labels', () => { it('Plural signature is present', () => { - expect(aid(`${testContext.prefix}pluralize-left`).textContent.trim()).toBe( - 'лет', - ); - expect(aid(`${testContext.prefix}pluralize-right`).textContent.trim()).toBe( - 'год', - ); - }); - - it('minLabel not shown at start > min', () => { - expect( - pageObject.getByAutomationId(`${testContext.prefix}min-label`), - ).toBeNull(); + expect(getLeftValueContent()).toBe(`0${CHAR_NO_BREAK_SPACE}лет`); + expect(getRightValueContent()).toBe(`1${CHAR_NO_BREAK_SPACE}год`); }); it('minLabel is shown', () => { testComponent.control.setValue([-10, 10]); fixture.detectChanges(); - expect(aid(`${testContext.prefix}min-label`).textContent.trim()).toBe( - testComponent.minLabel, - ); + expect(getLeftValueContent()).toBe(testComponent.minLabel); }); it('minLabel missing on focus', () => { testComponent.control.setValue([-10, 10]); inputPOLeft.focus(); - expect( - pageObject.getByAutomationId(`${testContext.prefix}min-label`), - ).toBeNull(); - }); - - it('maxLabel not shown when end { - expect( - pageObject.getByAutomationId(`${testContext.prefix}min-label`), - ).toBeNull(); + expect(getLeftValueContent()).toBeNull(); + expect(getLeftValueDecoration()).toBe('0лет'); }); it('maxLabel is shown', () => { testComponent.control.setValue([-10, 10]); fixture.detectChanges(); - expect(aid(`${testContext.prefix}max-label`).textContent.trim()).toBe( - testComponent.maxLabel, - ); + expect(getRightValueContent()).toBe(testComponent.maxLabel); }); it('maxLabel missing on focus', () => { testComponent.control.setValue([-10, 10]); inputPORight.focus(); - expect( - pageObject.getByAutomationId(`${testContext.prefix}max-label`), - ).toBeNull(); + expect(getRightValueContent()).toBeNull(); + expect(getRightValueDecoration()).toBe('лет'); }); }); @@ -173,9 +158,13 @@ describe('InputRange', () => { expect(testComponent.control.value[0]).toBe(-5); }); - it('Rounds the left value of an input field to the nearest quantum when focus is lost', () => { + it('Rounds the left value of an input field to the nearest quantum when focus is lost', async () => { inputPOLeft.sendTextAndBlur('-7'); + await fixture.whenStable(); + fixture.detectChanges(); + await fixture.whenStable(); + expect(inputPOLeft.value).toBe('-5'); }); @@ -185,26 +174,34 @@ describe('InputRange', () => { expect(testComponent.control.value[1]).toBe(5); }); - it('Rounds the right value of an input field to the nearest quantum on loss of focus', () => { + it('Rounds the right value of an input field to the nearest quantum on loss of focus', async () => { inputPORight.sendTextAndBlur('7'); + await fixture.whenStable(); + fixture.detectChanges(); + await fixture.whenStable(); + expect(inputPORight.value).toBe('5'); }); }); describe('Deleting Values', () => { - it("Doesn't change value when left content is removed", () => { + it("Doesn't change value when left content is removed", async () => { inputPOLeft.sendTextAndBlur('-5'); inputPOLeft.sendTextAndBlur(''); + await fixture.whenStable(); + expect(testComponent.control.value[0]).toBe(-5); expect(inputPOLeft.value).toBe('-5'); }); - it("Doesn't change value when deleting right content", () => { + it("Doesn't change value when deleting right content", async () => { inputPORight.sendTextAndBlur('5'); inputPORight.sendTextAndBlur(''); + await fixture.whenStable(); + expect(testComponent.control.value[1]).toBe(5); expect(inputPORight.value).toBe('5'); }); @@ -220,7 +217,10 @@ describe('InputRange', () => { }); it('Prevents the right value from becoming less than the left value when leaving the field', () => { - inputPORight.sendTextAndBlur('-5'); + inputPOLeft.sendTextAndBlur('-5'); + fixture.detectChanges(); + + inputPORight.sendTextAndBlur('-10'); expect(testComponent.control.value[1]).toBe(testComponent.control.value[0]); expect(inputPORight.value).toBe(testComponent.control.value[0].toString()); @@ -405,4 +405,56 @@ describe('InputRange', () => { }); }); }); + + function getLeftValueContent(): string | null { + const valueContent = pageObject.getByAutomationId( + testContext.valueContentAutoId, + leftInputWrapper, + ); + + return valueContent && valueContent.nativeElement.textContent.trim(); + } + + function getRightValueContent(): string | null { + const valueContent = pageObject.getByAutomationId( + testContext.valueContentAutoId, + rightInputWrapper, + ); + + return valueContent && valueContent.nativeElement.textContent.trim(); + } + + function getLeftValueDecoration(): string { + return pageObject + .getByAutomationId(testContext.valueDecorationAutoId, leftInputWrapper) + ?.nativeElement.textContent.trim() + .replace('\n ', ''); + } + + function getRightValueDecoration(): string { + return pageObject + .getByAutomationId(`${testContext.prefix}pluralize-right`) + ?.nativeElement.textContent.trim() + .replace('\n ', ''); + } + + function initializeInputsPO() { + leftInputWrapper = fixture.debugElement.query( + By.css('tui-input-number:first-of-type'), + ); + rightInputWrapper = fixture.debugElement.query( + By.css('tui-input-number:last-of-type'), + ); + + inputPOLeft = new NativeInputPO( + fixture, + testContext.nativeInputAutoId, + leftInputWrapper, + ); + inputPORight = new NativeInputPO( + fixture, + testContext.nativeInputAutoId, + rightInputWrapper, + ); + } }); diff --git a/projects/kit/components/input-slider/input-slider.component.ts b/projects/kit/components/input-slider/input-slider.component.ts index 2f6933a1ba57f..2ae738f5f72d0 100644 --- a/projects/kit/components/input-slider/input-slider.component.ts +++ b/projects/kit/components/input-slider/input-slider.component.ts @@ -27,9 +27,7 @@ import { import { getFractionPartPadded, HINT_CONTROLLER_PROVIDER, - NumberFormatSettings, TEXTFIELD_CONTROLLER_PROVIDER, - TUI_NUMBER_FORMAT, TUI_TEXTFIELD_WATCHED_CONTROLLER, TuiDecimalT, TuiSizeL, @@ -130,14 +128,6 @@ export class TuiInputSliderComponent @tuiDefaultProp() postfix = ''; - /** - * @deprecated use `tuiTextfieldSize` instead - * TODO delete in v3.0 - */ - @Input() - @tuiDefaultProp() - size: TuiSizeL = 'l'; - /** * @deprecated use `tuiTextfieldCustomContent` instead * TODO delete in v3.0 @@ -154,8 +144,6 @@ export class TuiInputSliderComponent @Inject(ChangeDetectorRef) changeDetectorRef: ChangeDetectorRef, @Inject(TUI_TEXTFIELD_WATCHED_CONTROLLER) readonly controller: TuiTextfieldController, - @Inject(TUI_NUMBER_FORMAT) - protected readonly numberFormat: NumberFormatSettings, @Inject(TUI_FROM_TO_TEXTS) readonly fromToTexts$: Observable<[string, string]>, @Optional() @Inject(TuiNewInputSliderDirective) diff --git a/projects/testing/src/utils/native-input.page-object.ts b/projects/testing/src/utils/native-input.page-object.ts index c19c434e01528..508b72d1a2ad2 100644 --- a/projects/testing/src/utils/native-input.page-object.ts +++ b/projects/testing/src/utils/native-input.page-object.ts @@ -1,3 +1,4 @@ +import {DebugElement} from '@angular/core'; import {ComponentFixture} from '@angular/core/testing'; import {createKeyboardEvent} from './keyboard-event'; @@ -9,12 +10,16 @@ export class NativeInputPO { constructor( private readonly fixture: ComponentFixture, private readonly automationId: string, + private readonly hostDebugElement?: DebugElement, ) { this.pageObject = new PageObject(fixture); } get nativeElement(): any { - return this.pageObject.getByAutomationId(this.automationId)!.nativeElement; + return this.pageObject.getByAutomationId( + this.automationId, + this.hostDebugElement, + )!.nativeElement; } get value(): string {