@taiga-ui/kit
Version:
Taiga UI Angular main components kit
199 lines (194 loc) • 16.1 kB
JavaScript
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