UNPKG

@taiga-ui/kit

Version:

Taiga UI Angular main components kit

183 lines (178 loc) 18.4 kB
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