@taiga-ui/kit
Version:
Taiga UI Angular main components kit
183 lines (178 loc) • 18.4 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, output, Directive, viewChildren, input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
import * as i2 from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { TuiControl } from '@taiga-ui/cdk/classes';
import { tuiFallbackValueProvider } from '@taiga-ui/cdk/tokens';
import { tuiInjectElement, tuiIsElement, tuiIsInput } from '@taiga-ui/cdk/utils/dom';
import { tuiClamp, tuiRound, tuiQuantize } from '@taiga-ui/cdk/utils/math';
import * as i3 from '@taiga-ui/core/components/slider';
import { TUI_FLOATING_PRECISION, TuiSliderComponent, tuiPercentageToKeyStepValue, tuiKeyStepValueToPercentage, TuiSlider } from '@taiga-ui/core/components/slider';
import { DOCUMENT } from '@angular/common';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { tuiTypedFromEvent } from '@taiga-ui/cdk/observables';
import { tap, switchMap, identity, startWith, map, takeUntil, repeat } from 'rxjs';
class TuiRangeChange {
constructor() {
this.doc = inject(DOCUMENT);
this.el = tuiInjectElement();
this.range = inject(TuiRange);
this.activeThumbChange = output();
let activeThumb;
tuiTypedFromEvent(this.el, 'pointerdown', {
passive: true,
capture: true,
})
.pipe(tap(({ clientX, target, pointerId }) => {
activeThumb = this.detectActiveThumb(clientX, target);
const slideElement = this.range.thumbs()[activeThumb === 'start' ? 0 : 1];
slideElement.setPointerCapture(pointerId);
this.activeThumbChange.emit(activeThumb);
if (this.range.focusable()) {
this.el.focus();
}
}), switchMap((event) => tuiTypedFromEvent(this.doc, 'pointermove').pipe(tuiIsElement(event.target) && tuiIsInput(event.target)
? identity
: startWith(event))), map(({ clientX }) => this.getFractionFromEvents(clientX ?? 0)), takeUntil(tuiTypedFromEvent(this.doc, 'pointerup', { passive: true })), repeat(), takeUntilDestroyed())
.subscribe((fraction) => {
const value = this.range.toValue(fraction);
this.range.processValue(value, activeThumb === 'end');
});
}
getFractionFromEvents(clickClientX) {
const { left, right, width } = this.el.getBoundingClientRect();
const start = this.el.matches('[dir="rtl"] :scope') ? right : left;
const value = Math.abs(tuiClamp(clickClientX, left, right) - start);
return tuiRound(value / width, TUI_FLOATING_PRECISION);
}
detectActiveThumb(clientX, target) {
const [startThumb, endThumb] = this.range.thumbs();
switch (target) {
case endThumb:
return 'end';
case startThumb:
return 'start';
default:
return this.findNearestActiveThumb(clientX);
}
}
findNearestActiveThumb(clientX) {
const fraction = this.getFractionFromEvents(clientX);
const deltaStart = fraction * 100 - this.range.start();
const deltaEnd = fraction * 100 - 100 + this.range.end();
return Math.abs(deltaStart) > Math.abs(deltaEnd) ||
deltaEnd > 0 ||
(this.range.start() === 0 && this.range.end() === 100)
? 'end'
: 'start';
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiRangeChange, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: TuiRangeChange, isStandalone: true, outputs: { activeThumbChange: "activeThumbChange" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiRangeChange, decorators: [{
type: Directive
}], ctorParameters: () => [] });
class TuiRange extends TuiControl {
constructor() {
super(...arguments);
this.el = tuiInjectElement();
this.sliders = viewChildren(TuiSliderComponent);
this.lastActiveThumb = 'end';
this.min = input(0);
this.max = input(100);
this.step = input(1);
this.segments = input(1);
this.keySteps = input();
this.focusable = input(true);
this.margin = input(0);
this.limit = input(Infinity);
this.start = computed(() => this.toPercent(this.value()[0]));
this.end = computed(() => 100 - this.toPercent(this.value()[1]));
this.thumbs = computed(([start, end] = this.sliders()) => [start.el, end.el]);
this.segmentWidthRatio = computed(() => 1 / this.segments());
this.fractionStep = computed((step = this.step()) => this.keySteps() ? step / 100 : step / (this.max() - this.min()));
this.computedKeySteps = computed(() => this.keySteps() || [
[0, this.min()],
[100, this.max()],
]);
}
processValue(value, end) {
if (end) {
this.updateEnd(value);
}
else {
this.updateStart(value);
}
this.lastActiveThumb = end ? 'end' : 'start';
}
takeStep(coefficients) {
return this.value().map((value, i) => {
const fraction = this.toPercent(value) / 100;
const newFractionValue = fraction + coefficients[i] * this.fractionStep();
return this.toValue(newFractionValue);
});
}
toValue(fraction) {
return tuiPercentageToKeyStepValue(tuiClamp(tuiQuantize(fraction, this.fractionStep()), 0, 1) * 100, this.computedKeySteps());
}
get rtl() {
return this.el.matches('[dir="rtl"] :scope');
}
changeByStep(coefficient, target) {
const [startThumb, endThumb] = this.thumbs();
const isEndThumb = target === this.el ? this.lastActiveThumb === 'end' : target === endThumb;
const activeThumbElement = isEndThumb ? endThumb : startThumb;
const newValue = this.takeStep(isEndThumb ? [0, coefficient] : [coefficient, 0]);
this.processValue(newValue[isEndThumb ? 1 : 0], isEndThumb);
activeThumbElement?.focus();
}
toPercent(value) {
return tuiKeyStepValueToPercentage(value, this.computedKeySteps());
}
updateStart(value) {
const newValue = Math.min(value, this.value()[1]);
const distance = this.value()[1] - newValue;
if (!this.checkDistance(distance)) {
return;
}
this.onChange([newValue, this.value()[1]]);
}
updateEnd(value) {
const newValue = Math.max(value, this.value()[0]);
const distance = newValue - this.value()[0];
if (!this.checkDistance(distance)) {
return;
}
this.onChange([this.value()[0], newValue]);
}
checkDistance(distance) {
return tuiClamp(distance, this.margin(), this.limit()) === distance;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiRange, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.21", type: TuiRange, isStandalone: true, selector: "tui-range", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, segments: { classPropertyName: "segments", publicName: "segments", isSignal: true, isRequired: false, transformFunction: null }, keySteps: { classPropertyName: "keySteps", publicName: "keySteps", isSignal: true, isRequired: false, transformFunction: null }, focusable: { classPropertyName: "focusable", publicName: "focusable", isSignal: true, isRequired: false, transformFunction: null }, margin: { classPropertyName: "margin", publicName: "margin", isSignal: true, isRequired: false, transformFunction: null }, limit: { classPropertyName: "limit", publicName: "limit", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "focusout": "onTouched()", "keydown.arrowDown.prevent": "changeByStep(-1, $event.target)", "keydown.arrowLeft.prevent": "changeByStep(rtl ? 1 : -1, $event.target)", "keydown.arrowRight.prevent": "changeByStep(rtl ? -1 : 1, $event.target)", "keydown.arrowUp.prevent": "changeByStep(1, $event.target)" }, properties: { "attr.aria-disabled": "disabled()", "attr.tabindex": "-1", "class._disabled": "disabled()", "style.--t-end.%": "end()", "style.--t-start.%": "start()" } }, providers: [tuiFallbackValueProvider([0, 0])], viewQueries: [{ propertyName: "sliders", predicate: TuiSliderComponent, descendants: true, isSignal: true }], usesInheritance: true, hostDirectives: [{ directive: TuiRangeChange, outputs: ["activeThumbChange", "activeThumbChange"] }], ngImport: i0, template: "<div\n class=\"t-track\"\n [style.--t-bg-size-ratio]=\"1 - segmentWidthRatio()\"\n [style.--t-segment-width.%]=\"segmentWidthRatio() * 100\"\n>\n <input\n automation-id=\"tui-range__left\"\n readonly\n tuiSlider\n type=\"range\"\n class=\"t-thumb\"\n [disabled]=\"disabled()\"\n [keySteps]=\"keySteps()\"\n [max]=\"max()\"\n [min]=\"min()\"\n [ngModel]=\"value()[0]\"\n [ngModelOptions]=\"{standalone: true}\"\n [step]=\"step()\"\n [tabIndex]=\"focusable() ? 0 : -1\"\n />\n <input\n automation-id=\"tui-range__right\"\n readonly\n tuiSlider\n type=\"range\"\n class=\"t-thumb\"\n [disabled]=\"disabled()\"\n [keySteps]=\"keySteps()\"\n [max]=\"max()\"\n [min]=\"min()\"\n [ngModel]=\"value()[1]\"\n [ngModelOptions]=\"{standalone: true}\"\n [step]=\"step()\"\n [tabIndex]=\"focusable() ? 0 : -1\"\n />\n</div>\n", styles: [":host{position:relative;display:block;block-size:max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem);border-radius:var(--tui-radius-m);cursor:pointer;outline:none;margin:calc((1rem - max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem))/2) 0;touch-action:pan-x;color:var(--tui-background-accent-1);background:var(--tui-background-neutral-2)}:host:active{cursor:ew-resize}:host:after{content:\"\";position:absolute;inset:calc((1rem - max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem))/-2) 0}:host._disabled{opacity:var(--tui-disabled-opacity);pointer-events:none}:host .t-track{position:relative;margin:0 var(--tui-thumb-size, .75rem);block-size:100%}:host .t-track:before{content:\"\";position:absolute;inset-block-start:0;inset-inline-start:calc(var(--t-start) - var(--tui-thumb-size, .75rem) / 3);inset-inline-end:calc(var(--t-end) - var(--tui-thumb-size, .75rem) / 3);block-size:100%;background:currentColor}:host .t-track:after{content:\"\";position:absolute;inset:0;inset-inline-start:-.125rem;inset-inline-end:.125rem;background:repeating-linear-gradient(to var(--tui-inline-end),var(--tui-text-tertiary) 0 .25rem,transparent 0 calc(var(--t-segment-width) / var(--t-bg-size-ratio))) var(--tui-inline-end) 0 / calc(100% * var(--t-bg-size-ratio)) no-repeat}:host .t-thumb{pointer-events:none;position:absolute;inset:50% calc(-5 * var(--tui-thumb-size, .75rem) / 12) auto;z-index:1;inline-size:auto;margin:0;opacity:1;transform:translateY(-50%);color:inherit;background:transparent}:host .t-thumb::-webkit-slider-thumb{pointer-events:auto}:host .t-thumb::-moz-range-thumb{pointer-events:auto}:host._disabled :host .t-thumb::-webkit-slider-thumb{pointer-events:none}:host._disabled :host .t-thumb::-moz-range-thumb{pointer-events:none}:host .t-thumb:first-of-type{--tui-slider-thumb-transform: translateX(calc(var(--tui-inline) * -50%)) translateX(calc(var(--tui-inline) * var(--tui-thumb-size, .75rem) / -12))}:host .t-thumb:last-of-type{--tui-slider-thumb-transform: translateX(calc(var(--tui-inline) * 50%)) translateX(calc(var(--tui-inline) * var(--tui-thumb-size, .75rem) / 12))}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.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: i2.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3.TuiSliderComponent, selector: "input[type=range][tuiSlider]", inputs: ["segments"] }, { kind: "directive", type: i3.TuiSliderKeyStepsBase, selector: "input[tuiSlider][keySteps]", inputs: ["step", "keySteps"] }, { kind: "directive", type: i3.TuiSliderKeySteps, selector: "input[tuiSlider][keySteps][ngModel],input[tuiSlider][keySteps][formControl],input[tuiSlider][keySteps][formControlName]", inputs: ["keySteps"] }, { kind: "directive", type: i3.TuiSliderReadonly, selector: "input[tuiSlider][readonly]", inputs: ["readonly"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: TuiRange, decorators: [{
type: Component,
args: [{ selector: 'tui-range', imports: [FormsModule, TuiSlider], changeDetection: ChangeDetectionStrategy.OnPush, providers: [tuiFallbackValueProvider([0, 0])], hostDirectives: [
{
directive: TuiRangeChange,
outputs: ['activeThumbChange'],
},
], host: {
'[attr.aria-disabled]': 'disabled()',
'[attr.tabindex]': '-1',
'[class._disabled]': 'disabled()',
'[style.--t-end.%]': 'end()',
'[style.--t-start.%]': 'start()',
'(focusout)': 'onTouched()',
'(keydown.arrowDown.prevent)': 'changeByStep(-1, $event.target)',
'(keydown.arrowLeft.prevent)': 'changeByStep(rtl ? 1 : -1, $event.target)',
'(keydown.arrowRight.prevent)': 'changeByStep(rtl ? -1 : 1, $event.target)',
'(keydown.arrowUp.prevent)': 'changeByStep(1, $event.target)',
}, template: "<div\n class=\"t-track\"\n [style.--t-bg-size-ratio]=\"1 - segmentWidthRatio()\"\n [style.--t-segment-width.%]=\"segmentWidthRatio() * 100\"\n>\n <input\n automation-id=\"tui-range__left\"\n readonly\n tuiSlider\n type=\"range\"\n class=\"t-thumb\"\n [disabled]=\"disabled()\"\n [keySteps]=\"keySteps()\"\n [max]=\"max()\"\n [min]=\"min()\"\n [ngModel]=\"value()[0]\"\n [ngModelOptions]=\"{standalone: true}\"\n [step]=\"step()\"\n [tabIndex]=\"focusable() ? 0 : -1\"\n />\n <input\n automation-id=\"tui-range__right\"\n readonly\n tuiSlider\n type=\"range\"\n class=\"t-thumb\"\n [disabled]=\"disabled()\"\n [keySteps]=\"keySteps()\"\n [max]=\"max()\"\n [min]=\"min()\"\n [ngModel]=\"value()[1]\"\n [ngModelOptions]=\"{standalone: true}\"\n [step]=\"step()\"\n [tabIndex]=\"focusable() ? 0 : -1\"\n />\n</div>\n", styles: [":host{position:relative;display:block;block-size:max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem);border-radius:var(--tui-radius-m);cursor:pointer;outline:none;margin:calc((1rem - max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem))/2) 0;touch-action:pan-x;color:var(--tui-background-accent-1);background:var(--tui-background-neutral-2)}:host:active{cursor:ew-resize}:host:after{content:\"\";position:absolute;inset:calc((1rem - max(calc(calc(var(--tui-thumb-size, .75rem) / 2) - .25rem),.125rem))/-2) 0}:host._disabled{opacity:var(--tui-disabled-opacity);pointer-events:none}:host .t-track{position:relative;margin:0 var(--tui-thumb-size, .75rem);block-size:100%}:host .t-track:before{content:\"\";position:absolute;inset-block-start:0;inset-inline-start:calc(var(--t-start) - var(--tui-thumb-size, .75rem) / 3);inset-inline-end:calc(var(--t-end) - var(--tui-thumb-size, .75rem) / 3);block-size:100%;background:currentColor}:host .t-track:after{content:\"\";position:absolute;inset:0;inset-inline-start:-.125rem;inset-inline-end:.125rem;background:repeating-linear-gradient(to var(--tui-inline-end),var(--tui-text-tertiary) 0 .25rem,transparent 0 calc(var(--t-segment-width) / var(--t-bg-size-ratio))) var(--tui-inline-end) 0 / calc(100% * var(--t-bg-size-ratio)) no-repeat}:host .t-thumb{pointer-events:none;position:absolute;inset:50% calc(-5 * var(--tui-thumb-size, .75rem) / 12) auto;z-index:1;inline-size:auto;margin:0;opacity:1;transform:translateY(-50%);color:inherit;background:transparent}:host .t-thumb::-webkit-slider-thumb{pointer-events:auto}:host .t-thumb::-moz-range-thumb{pointer-events:auto}:host._disabled :host .t-thumb::-webkit-slider-thumb{pointer-events:none}:host._disabled :host .t-thumb::-moz-range-thumb{pointer-events:none}:host .t-thumb:first-of-type{--tui-slider-thumb-transform: translateX(calc(var(--tui-inline) * -50%)) translateX(calc(var(--tui-inline) * var(--tui-thumb-size, .75rem) / -12))}:host .t-thumb:last-of-type{--tui-slider-thumb-transform: translateX(calc(var(--tui-inline) * 50%)) translateX(calc(var(--tui-inline) * var(--tui-thumb-size, .75rem) / 12))}\n"] }]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { TuiRange, TuiRangeChange };
//# sourceMappingURL=taiga-ui-kit-components-range.mjs.map