UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

199 lines (194 loc) 16.1 kB
import { TuiLabel } from '@taiga-ui/core/components/label'; import { NgIf } from '@angular/common'; import * as i0 from '@angular/core'; import { inject, signal, computed, ElementRef, Component, ChangeDetectionStrategy, ViewChildren, ViewChild, Input } from '@angular/core'; import * as i1 from '@angular/forms'; import { FormsModule } from '@angular/forms'; import { TuiControl, tuiAsControl } from '@taiga-ui/cdk/classes'; import { EMPTY_QUERY, CHAR_NO_BREAK_SPACE, CHAR_EN_DASH } from '@taiga-ui/cdk/constants'; import { TUI_IS_MOBILE, tuiFallbackValueProvider } from '@taiga-ui/cdk/tokens'; import { tuiIsNativeFocused } from '@taiga-ui/cdk/utils/focus'; import * as i3 from '@taiga-ui/core/components/textfield'; import { TUI_TEXTFIELD_OPTIONS, TuiTextfield } from '@taiga-ui/core/components/textfield'; import * as i2 from '@taiga-ui/kit/components/input-number'; import { TuiQuantumValueTransformerBase, TuiInputNumberDirective, TuiInputNumber } from '@taiga-ui/kit/components/input-number'; import { TuiRange } from '@taiga-ui/kit/components/range'; import { tuiSliderOptionsProvider } from '@taiga-ui/kit/components/slider'; import { PolymorpheusOutlet } from '@taiga-ui/polymorpheus'; class TuiInputRangeComponent extends TuiControl { constructor() { super(...arguments); this.inputNumberRefs = EMPTY_QUERY; this.isMobile = inject(TUI_IS_MOBILE); this.quantum = signal(0); this.quantumTransformer = computed(() => new TuiQuantumValueTransformerBase(this.quantum())); this.size = inject(TUI_TEXTFIELD_OPTIONS).size; this.textfieldValueStart = this.value()[0]; this.textfieldValueEnd = this.value()[1]; this.lastActiveSide = 'start'; this.content = signal(['', '']); this.contentStart = computed(() => { const [start, end] = this.content().map((x, i) => { const value = this.value()[i]; return typeof x === 'function' ? x({ $implicit: value }) : x || value; }); if (this.interactive() || !this.isPrimitive(start) || !this.isPrimitive(end)) { return this.content()[0]; } return `${start}${CHAR_NO_BREAK_SPACE}${CHAR_EN_DASH}${CHAR_NO_BREAK_SPACE}${end}`; }); this.contentEnd = computed(() => this.contentStart() === this.content()[0] ? this.content()[1] : ''); this.min = 0; this.max = 100; this.step = 1; this.segments = 1; this.keySteps = null; this.prefix = ['', '']; this.postfix = ['', '']; } // TODO(v5): use signal inputs set quantumSetter(x) { this.quantum.set(x); } // TODO(v5): use signal inputs set contentSetter(x) { this.content.set(x); } writeValue(value) { super.writeValue(value); this.setTextfieldValues(this.value()); } ngAfterViewInit() { if (this.range) { this.range.legacyMode = false; // TODO(v5): remove backward compatibility } } get contentStartHidden() { return this.interactive() && tuiIsNativeFocused(this.textfieldStart); } get contentEndHidden() { return (!this.content()[1] || (this.interactive() && tuiIsNativeFocused(this.textfieldEnd))); } takeStep(event, coefficients) { if (!this.interactive() || !this.range) { return; } event.preventDefault(); const [start, end] = this.value(); const newValue = this.valueGuard(this.range.takeStep(coefficients)); if (newValue[0] !== start || newValue[1] !== end) { this.onExternalValueUpdate(newValue); } } onInput([start, end]) { const [prevStart, prevEnd] = this.value(); this.setValue([start ?? prevStart, end ?? prevEnd]); } onExternalValueUpdate(value) { this.setValue(value); this.setTextfieldValues(this.value()); setTimeout((end = Number.MAX_SAFE_INTEGER) => { if (tuiIsNativeFocused(this.activeTextfield)) { this.activeTextfield?.setSelectionRange(end, end); } }); } focusToTextfield() { if (!this.isMobile) { this.activeTextfield?.focus(); } } onBlur() { this.onTouched(); this.setTextfieldValues(this.value()); } onActiveThumbChange(activeThumb) { // TODO(v5): remove backward compatibility this.lastActiveSide = activeThumb === 'left' ? 'start' : 'end'; } setTextfieldValues([start, end]) { this.textfieldValueStart = start; this.textfieldValueEnd = end; } get textfieldStart() { return this.inputNumberRefs.first?.nativeElement || null; } get textfieldEnd() { return this.inputNumberRefs.last?.nativeElement || null; } get activeTextfield() { return this.lastActiveSide === 'start' ? this.textfieldStart : this.textfieldEnd; } setValue(value) { this.onChange(this.valueGuard(value)); } valueGuard(value) { const [prevStart, prevEnd] = this.value(); const [start, end] = value.map((x) => this.quantumTransformer().toControlValue(x) ?? x); return [Math.min(start, prevEnd), Math.max(end, prevStart)]; } isPrimitive(x) { return Object(x) !== x; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiInputRangeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: TuiInputRangeComponent, isStandalone: true, selector: "tui-input-range", inputs: { min: "min", max: "max", step: "step", segments: "segments", keySteps: "keySteps", prefix: ["prefix", "prefix", (x) => x ?? ['', '']], postfix: ["postfix", "postfix", (x) => x ?? ['', '']], quantumSetter: ["quantum", "quantumSetter"], contentSetter: ["content", "contentSetter"] }, host: { attributes: { "new": "" }, properties: { "attr.data-size": "size()", "style.--t-icon-lock": "contentEnd() ? \"none\" : null" } }, providers: [ tuiAsControl(TuiInputRangeComponent), tuiSliderOptionsProvider({ trackColor: 'transparent' }), tuiFallbackValueProvider([0, 0]), ], viewQueries: [{ propertyName: "range", first: true, predicate: TuiRange, descendants: true }, { propertyName: "inputNumberRefs", predicate: TuiInputNumberDirective, descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: "<tui-textfield [content]=\"contentStartHidden ? '' : contentStart()\">\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\" />\n </ng-container>\n\n <input\n tuiInputNumber\n [disabled]=\"disabled()\"\n [invalid]=\"invalid()\"\n [max]=\"value()[1]\"\n [min]=\"min\"\n [postfix]=\"postfix[0]\"\n [prefix]=\"prefix[0]\"\n [readOnly]=\"readOnly()\"\n [(ngModel)]=\"textfieldValueStart\"\n (blur)=\"onBlur()\"\n (keydown.arrowDown)=\"takeStep($event, [-1, 0])\"\n (keydown.arrowUp)=\"takeStep($event, [1, 0])\"\n (ngModelChange)=\"onInput([$event, null])\"\n />\n\n <input\n tuiInputNumber\n tuiTextfieldAppearance=\"none\"\n class=\"t-end\"\n [class._hidden]=\"!contentEndHidden || !this.interactive()\"\n [disabled]=\"disabled()\"\n [invalid]=\"invalid()\"\n [max]=\"max\"\n [min]=\"value()[0]\"\n [postfix]=\"postfix[1]\"\n [prefix]=\"prefix[1]\"\n [readOnly]=\"readOnly()\"\n [(ngModel)]=\"textfieldValueEnd\"\n (blur)=\"onBlur()\"\n (keydown.arrowDown)=\"takeStep($event, [0, -1])\"\n (keydown.arrowUp)=\"takeStep($event, [0, 1])\"\n (ngModelChange)=\"onInput([null, $event])\"\n />\n\n <div\n class=\"t-content-end\"\n [class._hidden]=\"contentEndHidden\"\n >\n <ng-container *polymorpheusOutlet=\"contentEnd() as text; context: {$implicit: value()[1]}\">\n {{ text }}\n </ng-container>\n </div>\n</tui-textfield>\n\n<tui-range\n *ngIf=\"interactive()\"\n [focusable]=\"false\"\n [keySteps]=\"keySteps\"\n [max]=\"max\"\n [min]=\"min\"\n [ngModel]=\"value()\"\n [segments]=\"segments\"\n [step]=\"step\"\n (activeThumbChange)=\"onActiveThumbChange($event)\"\n (mousedown.prevent)=\"focusToTextfield()\"\n (ngModelChange)=\"onExternalValueUpdate($event)\"\n/>\n", styles: [":host{position:relative;display:block}.t-end{position:absolute;top:0;bottom:0;right:0;left:50%;display:flex;inline-size:50%;text-align:end;outline:none!important;border:none;padding-inline-end:var(--t-padding);color:var(--tui-text-primary);transition:none}.t-end:dir(rtl){right:unset;inset-inline-end:0}.t-content-end{color:var(--tui-text-primary)}tui-textfield:has(label:not(:empty)) .t-content-end{padding-block-start:calc(var(--t-height) / 3)}tui-textfield._with-label .t-content-end{padding-block-start:calc(var(--t-height) / 3)}._hidden._hidden{opacity:0}tui-range{position:absolute;top:100%;left:1rem;right:1rem;z-index:1;margin:calc(-1 * var(--tui-thickness)) 0 0}:host[data-size=m] tui-range{right:.75rem;left:.75rem}:host[data-size=s] tui-range{right:.625rem;left:.625rem}tui-textfield::ng-deep .t-clear{display:none!important}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "directive", type: i2.TuiInputNumberDirective, selector: "input[tuiInputNumber]", inputs: ["min", "max", "prefix", "postfix"] }, { kind: "component", type: TuiRange, selector: "tui-range", inputs: ["min", "max", "step", "size", "segments", "keySteps", "focusable", "margin", "limit"] }, { kind: "component", type: i3.TuiTextfieldComponent, selector: "tui-textfield:not([multi])" }, { kind: "directive", type: i3.TuiTextfieldOptionsDirective, selector: "[tuiTextfieldAppearance],[tuiTextfieldSize],[tuiTextfieldCleaner]", inputs: ["tuiTextfieldAppearance", "tuiTextfieldSize", "tuiTextfieldCleaner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiInputRangeComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'tui-input-range', imports: [ FormsModule, NgIf, PolymorpheusOutlet, TuiInputNumber, TuiRange, TuiTextfield, ], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ tuiAsControl(TuiInputRangeComponent), tuiSliderOptionsProvider({ trackColor: 'transparent' }), tuiFallbackValueProvider([0, 0]), ], host: { new: '', // TODO: use css :host:has(tui-textfield[data-size]) after browser bump '[attr.data-size]': 'size()', '[style.--t-icon-lock]': 'contentEnd() ? "none" : null', }, template: "<tui-textfield [content]=\"contentStartHidden ? '' : contentStart()\">\n <ng-container ngProjectAs=\"label\">\n <ng-content select=\"label\" />\n </ng-container>\n\n <input\n tuiInputNumber\n [disabled]=\"disabled()\"\n [invalid]=\"invalid()\"\n [max]=\"value()[1]\"\n [min]=\"min\"\n [postfix]=\"postfix[0]\"\n [prefix]=\"prefix[0]\"\n [readOnly]=\"readOnly()\"\n [(ngModel)]=\"textfieldValueStart\"\n (blur)=\"onBlur()\"\n (keydown.arrowDown)=\"takeStep($event, [-1, 0])\"\n (keydown.arrowUp)=\"takeStep($event, [1, 0])\"\n (ngModelChange)=\"onInput([$event, null])\"\n />\n\n <input\n tuiInputNumber\n tuiTextfieldAppearance=\"none\"\n class=\"t-end\"\n [class._hidden]=\"!contentEndHidden || !this.interactive()\"\n [disabled]=\"disabled()\"\n [invalid]=\"invalid()\"\n [max]=\"max\"\n [min]=\"value()[0]\"\n [postfix]=\"postfix[1]\"\n [prefix]=\"prefix[1]\"\n [readOnly]=\"readOnly()\"\n [(ngModel)]=\"textfieldValueEnd\"\n (blur)=\"onBlur()\"\n (keydown.arrowDown)=\"takeStep($event, [0, -1])\"\n (keydown.arrowUp)=\"takeStep($event, [0, 1])\"\n (ngModelChange)=\"onInput([null, $event])\"\n />\n\n <div\n class=\"t-content-end\"\n [class._hidden]=\"contentEndHidden\"\n >\n <ng-container *polymorpheusOutlet=\"contentEnd() as text; context: {$implicit: value()[1]}\">\n {{ text }}\n </ng-container>\n </div>\n</tui-textfield>\n\n<tui-range\n *ngIf=\"interactive()\"\n [focusable]=\"false\"\n [keySteps]=\"keySteps\"\n [max]=\"max\"\n [min]=\"min\"\n [ngModel]=\"value()\"\n [segments]=\"segments\"\n [step]=\"step\"\n (activeThumbChange)=\"onActiveThumbChange($event)\"\n (mousedown.prevent)=\"focusToTextfield()\"\n (ngModelChange)=\"onExternalValueUpdate($event)\"\n/>\n", styles: [":host{position:relative;display:block}.t-end{position:absolute;top:0;bottom:0;right:0;left:50%;display:flex;inline-size:50%;text-align:end;outline:none!important;border:none;padding-inline-end:var(--t-padding);color:var(--tui-text-primary);transition:none}.t-end:dir(rtl){right:unset;inset-inline-end:0}.t-content-end{color:var(--tui-text-primary)}tui-textfield:has(label:not(:empty)) .t-content-end{padding-block-start:calc(var(--t-height) / 3)}tui-textfield._with-label .t-content-end{padding-block-start:calc(var(--t-height) / 3)}._hidden._hidden{opacity:0}tui-range{position:absolute;top:100%;left:1rem;right:1rem;z-index:1;margin:calc(-1 * var(--tui-thickness)) 0 0}:host[data-size=m] tui-range{right:.75rem;left:.75rem}:host[data-size=s] tui-range{right:.625rem;left:.625rem}tui-textfield::ng-deep .t-clear{display:none!important}\n"] }] }], propDecorators: { inputNumberRefs: [{ type: ViewChildren, args: [TuiInputNumberDirective, { read: ElementRef }] }], range: [{ type: ViewChild, args: [TuiRange] }], min: [{ type: Input }], max: [{ type: Input }], step: [{ type: Input }], segments: [{ type: Input }], keySteps: [{ type: Input }], prefix: [{ type: Input, args: [{ transform: (x) => x ?? ['', ''] }] }], postfix: [{ type: Input, args: [{ transform: (x) => x ?? ['', ''] }] }], quantumSetter: [{ type: Input, args: ['quantum'] }], contentSetter: [{ type: Input, args: ['content'] }] } }); const TuiInputRange = [TuiInputRangeComponent, TuiLabel]; /** * Generated bundle index. Do not edit. */ export { TuiInputRange, TuiInputRangeComponent }; //# sourceMappingURL=taiga-ui-kit-components-input-range.mjs.map