@taiga-ui/kit
Version:
Taiga UI Angular main components kit
385 lines (375 loc) • 36.7 kB
JavaScript
import { tuiRound } from '@taiga-ui/cdk/utils/math';
import { __decorate } from 'tslib';
import * as i0 from '@angular/core';
import { InjectionToken, inject, signal, computed, Component, ChangeDetectionStrategy, Input, INJECTOR, Directive, forwardRef, ContentChild } from '@angular/core';
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { NgControl, NgModel } from '@angular/forms';
import { TuiControl } from '@taiga-ui/cdk/classes';
import { tuiWatch, tuiControlValue, tuiTypedFromEvent } from '@taiga-ui/cdk/observables';
import { tuiFallbackValueProvider } from '@taiga-ui/cdk/tokens';
import { tuiProvideOptions, tuiPure } from '@taiga-ui/cdk/utils/miscellaneous';
import { take, timer, switchMap, merge, tap, map, combineLatest, filter } from 'rxjs';
import { tuiInjectElement } from '@taiga-ui/cdk/utils/dom';
import { tuiAsAuxiliary } from '@taiga-ui/core/tokens';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { DOCUMENT, AsyncPipe, NgIf } from '@angular/common';
import { TUI_TRUE_HANDLER, TUI_FALSE_HANDLER } from '@taiga-ui/cdk/constants';
import { tuiHintOptionsProvider } from '@taiga-ui/core/directives/hint';
/**
* Used as a limit for eliminating JS issues with floating point math
*/
const TUI_FLOATING_PRECISION = 7;
function tuiFindKeyStepsBoundariesByFn(keySteps, fn) {
const keyStepUpperIndex = keySteps.findIndex((keyStep, i) => i && fn(keyStep));
const lowerStep = keySteps[keyStepUpperIndex - 1] || keySteps[0];
const upperStep = keySteps[keyStepUpperIndex] ||
keySteps[keySteps.length - 1] || [0, 0];
return [lowerStep, upperStep];
}
function tuiPercentageToKeyStepValue(valuePercentage, keySteps) {
const [[lowerStepPercent, lowerStepValue], [upperStepPercent, upperStepValue]] = tuiFindKeyStepsBoundariesByFn(keySteps, ([keyStepPercentage, _]) => valuePercentage <= keyStepPercentage);
const ratio = (valuePercentage - lowerStepPercent) / (upperStepPercent - lowerStepPercent);
const controlValue = (upperStepValue - lowerStepValue) * ratio + lowerStepValue;
return tuiRound(controlValue, TUI_FLOATING_PRECISION);
}
function tuiKeyStepValueToPercentage(value, keySteps) {
const [[lowerStepPercent, lowerStepValue], [upperStepPercent, upperStepValue]] = tuiFindKeyStepsBoundariesByFn(keySteps, ([_, keyStepValue]) => value <= keyStepValue);
const ratio = (value - lowerStepValue) / (upperStepValue - lowerStepValue) || 0;
return (upperStepPercent - lowerStepPercent) * ratio + lowerStepPercent;
}
function tuiCreateKeyStepsTransformer(keySteps, slider) {
return new (class {
fromControlValue(controlValue) {
const newValuePercentage = tuiKeyStepValueToPercentage(controlValue, keySteps);
return (newValuePercentage * (slider.max - slider.min)) / 100 + slider.min;
}
toControlValue(nativeValue) {
const valueRatio = (nativeValue - slider.min) / (slider.max - slider.min) || 0;
return tuiPercentageToKeyStepValue(valueRatio * 100, keySteps);
}
})();
}
const TUI_SLIDER_DEFAULT_OPTIONS = {
size: 'm',
trackColor: 'var(--tui-background-neutral-2)',
};
/**
* Default parameters for Slider component
*/
const TUI_SLIDER_OPTIONS = new InjectionToken(ngDevMode ? 'TUI_SLIDER_OPTIONS' : '', {
factory: () => TUI_SLIDER_DEFAULT_OPTIONS,
});
function tuiSliderOptionsProvider(options) {
return tuiProvideOptions(TUI_SLIDER_OPTIONS, options, TUI_SLIDER_DEFAULT_OPTIONS);
}
class TuiSliderComponent {
constructor() {
this.control = inject(NgControl, { self: true, optional: true });
this.options = inject(TUI_SLIDER_OPTIONS);
this.segments = signal([1]);
this.ticksGradient = computed((segments = this.segments()) => this.getTicksGradient(segments));
this.size = this.options.size;
this.el = tuiInjectElement();
this.keySteps = inject(TuiSliderKeyStepsBase, {
self: true,
optional: true,
});
if (this.control instanceof NgModel) {
/**
* The ValueAccessor.writeValue method is called twice on any value accessor during component initialization,
* when a control is bound using [(ngModel)], first time with a phantom null value.
* With `changeDetection: ChangeDetectionStrategy.OnPush` the second call of writeValue with real value don't re-render the view.
* ___
* See this {@link https://github.com/angular/angular/issues/14988 issue}
*/
this.control.valueChanges?.pipe(tuiWatch(), take(1)).subscribe();
}
}
// TODO(v5): use signal inputs
set segmentsSetter(segments) {
this.segments.set(segments);
}
get valueRatio() {
return (this.value - this.min) / (this.max - this.min) || 0;
}
get min() {
return Number(this.el.min);
}
set min(x) {
this.el.min = String(x);
}
get max() {
return Number(this.el.max || 100);
}
set max(x) {
this.el.max = String(x);
}
get step() {
if (!this.el.step) {
return 1;
}
return this.el.step === 'any' ? 0 : Number(this.el.step);
}
set step(x) {
this.el.step = String(x);
}
get value() {
/**
* If developer uses `[(ngModel)]` and programmatically change value,
* the `el.nativeElement.value` is equal to the previous value at this moment
* (it will be updated only in next microtask).
* @see https://github.com/angular/angular/issues/13568
*/
if (this.control instanceof NgModel) {
const transformer = this.keySteps?.transformer();
const value = transformer
? transformer.fromControlValue(this.control.value)
: this.control.viewModel;
return this.step
? tuiRound(Math.round(value / this.step) * this.step, TUI_FLOATING_PRECISION)
: value;
}
return Number(this.el.value) || 0;
}
set value(newValue) {
this.el.value = `${newValue}`;
}
getTicksGradient(segments) {
if (segments.length <= 1) {
return 'linear-gradient(to right, transparent 0 100%)';
}
const percentages = segments
.filter((segment) => segment > 0 && segment < 1)
.map((segment) => segment * 100);
return percentages.reduce((acc, segment, index) => `${acc}
var(--tui-text-tertiary) ${segment}% calc(${segment}% + var(--t-tick-thickness)),
transparent ${segment}% ${percentages[index + 1] ?? 100}%${percentages[index + 1] ? ',' : ')'}
`, `linear-gradient(to right, transparent 0 ${percentages[0]}%,`);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: TuiSliderComponent, isStandalone: true, selector: "input[type=range][tuiSlider]", inputs: { size: "size", segmentsSetter: ["segments", "segmentsSetter", (x) => Array.isArray(x) ? x : new Array(x).fill(null).map((_, i) => i / x)] }, host: { listeners: { "input": "0" }, properties: { "style.--tui-slider-track-color": "options.trackColor", "style.--tui-ticks-gradient": "ticksGradient()", "style.--tui-slider-fill-ratio": "valueRatio", "attr.data-size": "size" } }, providers: [tuiAsAuxiliary(TuiSliderComponent)], ngImport: i0, template: '', isInline: true, styles: [":host{--t-tick-thickness: .25rem;position:relative;display:block;inline-size:100%;color:var(--tui-background-accent-1);cursor:pointer;-webkit-appearance:none;appearance:none;block-size:.125rem;padding:.4375rem 0;background-color:transparent;background-clip:content-box;outline:none;border-radius:var(--tui-radius-m)}:host:active{cursor:ew-resize}:host:disabled{opacity:var(--tui-disabled-opacity);cursor:auto}:host[data-size=s]:not(:disabled):before{transition-property:transform,opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;top:.25rem;left:var(--t-left);inset-inline-start:var(--t-left);inline-size:.5rem;block-size:.5rem;border-radius:50%;transform:var(--tui-slider-thumb-transform, scale(1));--t-left: calc(var(--tui-slider-fill-ratio) * 100% - var(--tui-slider-fill-ratio) * .5rem);content:\"\";cursor:ew-resize;background:currentColor;opacity:0}:host[data-size=s]:active:before{opacity:.2;transform:var(--tui-slider-thumb-transform, scale(1)) scale(2.33)}:host[data-size=m]:not(:disabled):before{transition-property:transform,opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;top:.125rem;left:var(--t-left);inset-inline-start:var(--t-left);inline-size:.75rem;block-size:.75rem;border-radius:50%;transform:var(--tui-slider-thumb-transform, scale(1));--t-left: calc(var(--tui-slider-fill-ratio) * 100% - var(--tui-slider-fill-ratio) * .75rem);content:\"\";cursor:ew-resize;background:currentColor;opacity:0}:host[data-size=m]:active:before{opacity:.2;transform:var(--tui-slider-thumb-transform, scale(1)) scale(2.33)}:host::-webkit-slider-container{border-radius:inherit}:host[data-size=m]::-webkit-slider-runnable-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient),linear-gradient(to var(--tui-inline-end),currentColor calc(100% * var(--tui-slider-fill-ratio)),transparent calc(100% * var(--tui-slider-fill-ratio)));background-position-x:calc((.75rem - var(--t-tick-thickness)) / 2),0;background-size:calc(100% - .75rem),auto}:host[data-size=s]::-webkit-slider-runnable-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient),linear-gradient(to var(--tui-inline-end),currentColor calc(100% * var(--tui-slider-fill-ratio)),transparent calc(100% * var(--tui-slider-fill-ratio)));background-position-x:calc((.5rem - var(--t-tick-thickness)) / 2),0;background-size:calc(100% - .5rem),auto}:host[data-size=m]::-moz-range-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient);background-position-x:calc((.75rem - var(--t-tick-thickness)) / 2);background-size:calc(100% - .75rem)}:host[data-size=s]::-moz-range-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient);background-position-x:calc((.5rem - var(--t-tick-thickness)) / 2);background-size:calc(100% - .5rem)}:host[data-size=m]::-webkit-slider-thumb{-webkit-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.75rem;inline-size:.75rem;box-sizing:content-box;background-clip:content-box;border:.125rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1));margin-block-start:-.4375rem}:not(:disabled):host[data-size=m]::-webkit-slider-thumb{cursor:ew-resize}:not(:disabled):host[data-size=m]::-webkit-slider-thumb:hover,:active:not(:disabled):host[data-size=m]::-webkit-slider-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.333)}:focus-visible:host[data-size=m]::-webkit-slider-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=s]::-webkit-slider-thumb{-webkit-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.5rem;inline-size:.5rem;box-sizing:content-box;background-clip:content-box;border:.25rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1));margin-block-start:-.4375rem}:not(:disabled):host[data-size=s]::-webkit-slider-thumb{cursor:ew-resize}:not(:disabled):host[data-size=s]::-webkit-slider-thumb:hover,:active:not(:disabled):host[data-size=s]::-webkit-slider-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.5)}:focus-visible:host[data-size=s]::-webkit-slider-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=m]::-moz-range-thumb{-moz-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.75rem;inline-size:.75rem;box-sizing:content-box;background-clip:content-box;border:.125rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1))}:not(:disabled):host[data-size=m]::-moz-range-thumb{cursor:ew-resize}:not(:disabled):host[data-size=m]::-moz-range-thumb:hover,:active:not(:disabled):host[data-size=m]::-moz-range-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.333)}:focus-visible:host[data-size=m]::-moz-range-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=s]::-moz-range-thumb{-moz-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.5rem;inline-size:.5rem;box-sizing:content-box;background-clip:content-box;border:.25rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1))}:not(:disabled):host[data-size=s]::-moz-range-thumb{cursor:ew-resize}:not(:disabled):host[data-size=s]::-moz-range-thumb:hover,:active:not(:disabled):host[data-size=s]::-moz-range-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.5)}:focus-visible:host[data-size=s]::-moz-range-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host::-moz-range-progress{border-radius:inherit}:host::-moz-range-progress{block-size:.125rem;background:currentColor;border-top-right-radius:0;border-bottom-right-radius:0}:host-context(tui-textfield) :host([type=\"range\"]){--tui-radius: var(--tui-radius-m);position:absolute;top:100%;left:calc(var(--tui-radius) / 2);right:calc(var(--tui-radius) / 2);inline-size:calc(100% - calc(var(--tui-radius) / 2) * 2);box-sizing:border-box;block-size:1rem;margin:-.5625rem 0 0;padding:0;border-top-left-radius:0;border-bottom-left-radius:calc(var(--tui-radius) * 10) calc(var(--tui-radius) * 2);pointer-events:auto}:host-context(tui-textfield[data-size=\"l\"]) :host([type=\"range\"]){--tui-radius: var(--tui-radius-l)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderComponent, decorators: [{
type: Component,
args: [{ standalone: true, selector: 'input[type=range][tuiSlider]', template: '', changeDetection: ChangeDetectionStrategy.OnPush, providers: [tuiAsAuxiliary(TuiSliderComponent)], host: {
/**
* For change detection.
* Webkit does not have built-in method for customization of filling progress (as Firefox).
* We draw filling of progress by `background: linear-gradient(...)` of the track.
* This function triggers change detection (for {@link valueRatio} getter) when we drag thumb of the input.
*/
'(input)': '0',
'[style.--tui-slider-track-color]': 'options.trackColor',
'[style.--tui-ticks-gradient]': 'ticksGradient()',
'[style.--tui-slider-fill-ratio]': 'valueRatio',
'[attr.data-size]': 'size',
}, styles: [":host{--t-tick-thickness: .25rem;position:relative;display:block;inline-size:100%;color:var(--tui-background-accent-1);cursor:pointer;-webkit-appearance:none;appearance:none;block-size:.125rem;padding:.4375rem 0;background-color:transparent;background-clip:content-box;outline:none;border-radius:var(--tui-radius-m)}:host:active{cursor:ew-resize}:host:disabled{opacity:var(--tui-disabled-opacity);cursor:auto}:host[data-size=s]:not(:disabled):before{transition-property:transform,opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;top:.25rem;left:var(--t-left);inset-inline-start:var(--t-left);inline-size:.5rem;block-size:.5rem;border-radius:50%;transform:var(--tui-slider-thumb-transform, scale(1));--t-left: calc(var(--tui-slider-fill-ratio) * 100% - var(--tui-slider-fill-ratio) * .5rem);content:\"\";cursor:ew-resize;background:currentColor;opacity:0}:host[data-size=s]:active:before{opacity:.2;transform:var(--tui-slider-thumb-transform, scale(1)) scale(2.33)}:host[data-size=m]:not(:disabled):before{transition-property:transform,opacity;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;position:absolute;top:.125rem;left:var(--t-left);inset-inline-start:var(--t-left);inline-size:.75rem;block-size:.75rem;border-radius:50%;transform:var(--tui-slider-thumb-transform, scale(1));--t-left: calc(var(--tui-slider-fill-ratio) * 100% - var(--tui-slider-fill-ratio) * .75rem);content:\"\";cursor:ew-resize;background:currentColor;opacity:0}:host[data-size=m]:active:before{opacity:.2;transform:var(--tui-slider-thumb-transform, scale(1)) scale(2.33)}:host::-webkit-slider-container{border-radius:inherit}:host[data-size=m]::-webkit-slider-runnable-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient),linear-gradient(to var(--tui-inline-end),currentColor calc(100% * var(--tui-slider-fill-ratio)),transparent calc(100% * var(--tui-slider-fill-ratio)));background-position-x:calc((.75rem - var(--t-tick-thickness)) / 2),0;background-size:calc(100% - .75rem),auto}:host[data-size=s]::-webkit-slider-runnable-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient),linear-gradient(to var(--tui-inline-end),currentColor calc(100% * var(--tui-slider-fill-ratio)),transparent calc(100% * var(--tui-slider-fill-ratio)));background-position-x:calc((.5rem - var(--t-tick-thickness)) / 2),0;background-size:calc(100% - .5rem),auto}:host[data-size=m]::-moz-range-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient);background-position-x:calc((.75rem - var(--t-tick-thickness)) / 2);background-size:calc(100% - .75rem)}:host[data-size=s]::-moz-range-track{block-size:.125rem;border-radius:inherit;background-repeat:no-repeat;background-color:var(--tui-slider-track-color);background-image:var(--tui-ticks-gradient);background-position-x:calc((.5rem - var(--t-tick-thickness)) / 2);background-size:calc(100% - .5rem)}:host[data-size=m]::-webkit-slider-thumb{-webkit-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.75rem;inline-size:.75rem;box-sizing:content-box;background-clip:content-box;border:.125rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1));margin-block-start:-.4375rem}:not(:disabled):host[data-size=m]::-webkit-slider-thumb{cursor:ew-resize}:not(:disabled):host[data-size=m]::-webkit-slider-thumb:hover,:active:not(:disabled):host[data-size=m]::-webkit-slider-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.333)}:focus-visible:host[data-size=m]::-webkit-slider-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=s]::-webkit-slider-thumb{-webkit-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.5rem;inline-size:.5rem;box-sizing:content-box;background-clip:content-box;border:.25rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1));margin-block-start:-.4375rem}:not(:disabled):host[data-size=s]::-webkit-slider-thumb{cursor:ew-resize}:not(:disabled):host[data-size=s]::-webkit-slider-thumb:hover,:active:not(:disabled):host[data-size=s]::-webkit-slider-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.5)}:focus-visible:host[data-size=s]::-webkit-slider-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=m]::-moz-range-thumb{-moz-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.75rem;inline-size:.75rem;box-sizing:content-box;background-clip:content-box;border:.125rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1))}:not(:disabled):host[data-size=m]::-moz-range-thumb{cursor:ew-resize}:not(:disabled):host[data-size=m]::-moz-range-thumb:hover,:active:not(:disabled):host[data-size=m]::-moz-range-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.333)}:focus-visible:host[data-size=m]::-moz-range-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host[data-size=s]::-moz-range-thumb{-moz-transition-property:transform;transition-property:transform;transition-duration:var(--tui-duration, .3s);transition-timing-function:ease-in-out;isolation:isolate;-webkit-appearance:none;appearance:none;background-color:currentColor;box-shadow:none;border-radius:50%;block-size:.5rem;inline-size:.5rem;box-sizing:content-box;background-clip:content-box;border:.25rem solid transparent;border-inline-start:0;border-inline-end:0;transform:var(--tui-slider-thumb-transform, scale(1))}:not(:disabled):host[data-size=s]::-moz-range-thumb{cursor:ew-resize}:not(:disabled):host[data-size=s]::-moz-range-thumb:hover,:active:not(:disabled):host[data-size=s]::-moz-range-thumb{transform:var(--tui-slider-thumb-transform, scale(1)) scale(1.5)}:focus-visible:host[data-size=s]::-moz-range-thumb{box-shadow:0 0 0 2px inset var(--tui-border-focus)}:host::-moz-range-progress{border-radius:inherit}:host::-moz-range-progress{block-size:.125rem;background:currentColor;border-top-right-radius:0;border-bottom-right-radius:0}:host-context(tui-textfield) :host([type=\"range\"]){--tui-radius: var(--tui-radius-m);position:absolute;top:100%;left:calc(var(--tui-radius) / 2);right:calc(var(--tui-radius) / 2);inline-size:calc(100% - calc(var(--tui-radius) / 2) * 2);box-sizing:border-box;block-size:1rem;margin:-.5625rem 0 0;padding:0;border-top-left-radius:0;border-bottom-left-radius:calc(var(--tui-radius) * 10) calc(var(--tui-radius) * 2);pointer-events:auto}:host-context(tui-textfield[data-size=\"l\"]) :host([type=\"range\"]){--tui-radius: var(--tui-radius-l)}\n"] }]
}], ctorParameters: function () { return []; }, propDecorators: { size: [{
type: Input
}], segmentsSetter: [{
type: Input,
args: [{
alias: 'segments',
transform: (x) => Array.isArray(x) ? x : new Array(x).fill(null).map((_, i) => i / x),
}]
}] } });
class TuiSliderKeyStepsBase {
constructor() {
this.injector = inject(INJECTOR);
this.control = inject(NgControl, { self: true, optional: true });
this.step = 1;
this.transformer = signal(null);
this.value = toSignal(timer(0) // https://github.com/angular/angular/issues/54418
.pipe(switchMap(() => tuiControlValue(this.control))));
}
get slider() {
return this.injector.get(TuiSliderComponent);
}
set keySteps(steps) {
this.transformer.set(steps && tuiCreateKeyStepsTransformer(steps, this.slider));
this.min = steps?.[0][1];
this.max = steps?.[steps.length - 1]?.[1];
}
/**
* TODO(v5): standardize logic between `TuiSlider` & `TuiInputSlider` (for non-linear slider `step` means percentage)
* Add these host-bindings to `TuiSliderKeyStepsBase`:
* ```
* host: {
* '[attr.min]': '0',
* '[attr.step]': '1',
* '[attr.max]': 'totalSteps',
* },
* ```
*/
get totalSteps() {
/**
* Not-integer amount of steps is invalid usage of native sliders
* ```html
* <input type="range" [max]="100" [step]="3.33" />
* ```
* (impossible to select 100; 99.9 is max allowed value)
*/
return this.step ? Math.round(100 / this.step) : Infinity;
}
takeStep(coefficient) {
const newValue = this.slider.value + coefficient;
return (this.transformer()?.toControlValue(this.slider.value + coefficient) ??
newValue);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderKeyStepsBase, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "16.2.12", type: TuiSliderKeyStepsBase, isStandalone: true, selector: "input[tuiSlider][keySteps]", inputs: { step: ["step", "step", (x) => (x === 'any' ? null : x)], keySteps: "keySteps" }, host: { properties: { "attr.aria-valuemin": "min", "attr.aria-valuemax": "max", "attr.aria-valuenow": "value()" } }, ngImport: i0 }); }
}
__decorate([
tuiPure
], TuiSliderKeyStepsBase.prototype, "slider", null);
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderKeyStepsBase, decorators: [{
type: Directive,
args: [{
standalone: true,
selector: 'input[tuiSlider][keySteps]',
host: {
'[attr.aria-valuemin]': 'min',
'[attr.aria-valuemax]': 'max',
'[attr.aria-valuenow]': 'value()',
},
}]
}], propDecorators: { step: [{
type: Input,
args: [{ transform: (x) => (x === 'any' ? null : x) }]
}], slider: [], keySteps: [{
type: Input
}] } });
class TuiSliderKeySteps extends TuiControl {
constructor() {
super(...arguments);
this.slider = inject(forwardRef(() => TuiSliderComponent));
}
set keySteps(steps) {
this.transformer = tuiCreateKeyStepsTransformer(steps, this.slider);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderKeySteps, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: TuiSliderKeySteps, isStandalone: true, selector: "input[tuiSlider][keySteps][ngModel],input[tuiSlider][keySteps][formControl],input[tuiSlider][keySteps][formControlName]", inputs: { keySteps: "keySteps" }, host: { listeners: { "blur": "onTouched()", "input": "onChange($event.target.value)", "change": "onChange($event.target.value)" }, properties: { "value": "value()", "disabled": "disabled()" } }, providers: [tuiFallbackValueProvider(0)], usesInheritance: true, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderKeySteps, decorators: [{
type: Directive,
args: [{
standalone: true,
selector: 'input[tuiSlider][keySteps][ngModel],input[tuiSlider][keySteps][formControl],input[tuiSlider][keySteps][formControlName]',
providers: [tuiFallbackValueProvider(0)],
host: {
'[value]': 'value()',
'[disabled]': 'disabled()',
'(blur)': 'onTouched()',
'(input)': 'onChange($event.target.value)',
'(change)': 'onChange($event.target.value)',
},
}]
}], propDecorators: { keySteps: [{
type: Input
}] } });
const SLIDER_INTERACTION_KEYS = new Set([
'ArrowDown',
'ArrowLeft',
'ArrowRight',
'ArrowUp',
'End',
'Home',
'PageDown',
'PageUp',
]);
/**
* Native <input type='range' readonly> doesn't work.
* This directive imitates this native behaviour.
*/
class TuiSliderReadonly {
constructor() {
this.el = tuiInjectElement();
this.doc = inject(DOCUMENT);
this.readonly = true;
const touchStart$ = tuiTypedFromEvent(this.el, 'touchstart', {
passive: false,
});
const touchMove$ = tuiTypedFromEvent(this.doc, 'touchmove', {
passive: false,
});
const touchEnd$ = tuiTypedFromEvent(this.doc, 'touchend', {
passive: true,
});
const shouldPreventMove$ = merge(touchStart$.pipe(tap((e) => this.preventEvent(e)), map(TUI_TRUE_HANDLER)), touchEnd$.pipe(map(TUI_FALSE_HANDLER)));
/**
* @bad TODO think about another solution.
* Keep in mind that preventing touch event (on slider) inside `@HostListener('touchstart')` doesn't work for mobile chrome.
*/
combineLatest([touchMove$, shouldPreventMove$])
.pipe(filter(([_, shouldPreventMove]) => shouldPreventMove), takeUntilDestroyed())
.subscribe(([moveEvent]) => this.preventEvent(moveEvent));
}
preventEvent(event) {
if (event.cancelable && this.readonly) {
event.preventDefault();
}
}
preventKeyboardInteraction(event) {
if (SLIDER_INTERACTION_KEYS.has(event.key)) {
this.preventEvent(event);
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderReadonly, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "16.2.12", type: TuiSliderReadonly, isStandalone: true, selector: "input[tuiSlider][readonly]", inputs: { readonly: ["readonly", "readonly", coerceBooleanProperty] }, host: { listeners: { "keydown": "preventKeyboardInteraction($event)", "mousedown": "preventEvent($event)" } }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderReadonly, decorators: [{
type: Directive,
args: [{
standalone: true,
selector: 'input[tuiSlider][readonly]',
host: {
'(keydown)': 'preventKeyboardInteraction($event)',
'(mousedown)': 'preventEvent($event)',
},
}]
}], ctorParameters: function () { return []; }, propDecorators: { readonly: [{
type: Input,
args: [{ transform: coerceBooleanProperty }]
}] } });
/// <reference types="@taiga-ui/tsconfig/ng-dev-mode" />
/// <reference types="@taiga-ui/tsconfig/ng-dev-mode" />
class TuiSliderThumbLabel {
ngAfterContentInit() {
ngDevMode &&
console.assert(Boolean(this.control?.valueChanges), '\n[tuiSliderThumbLabel] expected <input tuiSlider type="range" /> to use Angular Forms.\n' +
'Use [(ngModel)] or [formControl] or formControlName for correct work.');
}
get size() {
return this.slider?.size || 'm';
}
get ratio() {
return this.slider?.valueRatio || 0;
}
get ghostStart() {
return this.ratio * (this.slider?.el.offsetWidth || 0);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderThumbLabel, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: TuiSliderThumbLabel, isStandalone: true, selector: "[tuiSliderThumbLabel]", providers: [tuiHintOptionsProvider({ direction: 'top', appearance: 'dark' })], queries: [{ propertyName: "slider", first: true, predicate: TuiSliderComponent, descendants: true }, { propertyName: "control", first: true, predicate: NgControl, descendants: true }], ngImport: i0, template: "<ng-container *ngIf=\"control?.valueChanges | async\" />\n\n<div\n class=\"t-ghost\"\n [attr.data-size]=\"size\"\n [style.--tui-slider-thumb-ratio]=\"ratio\"\n [style.inset-inline-start.px]=\"ghostStart\"\n [style.left.px]=\"ghostStart\"\n>\n <ng-content />\n</div>\n\n<ng-content select=\"input[type=range]\" />\n", styles: [":host{position:relative}.t-ghost{position:absolute;top:0;bottom:0;margin:auto;border-radius:50%;pointer-events:none}.t-ghost[data-size=s]{inline-size:.5rem;block-size:.5rem;transform:translate(calc(var(--tui-slider-thumb-ratio) * -.5rem * var(--tui-inline)))}.t-ghost[data-size=m]{inline-size:.75rem;block-size:.75rem;transform:translate(calc(var(--tui-slider-thumb-ratio) * -.75rem * var(--tui-inline)))}@supports (inset-inline-end: 0){:host-context([dir=\"rtl\"]) .t-ghost{left:unset!important}}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: TuiSliderThumbLabel, decorators: [{
type: Component,
args: [{ standalone: true, selector: '[tuiSliderThumbLabel]', imports: [AsyncPipe, NgIf], changeDetection: ChangeDetectionStrategy.OnPush, providers: [tuiHintOptionsProvider({ direction: 'top', appearance: 'dark' })], template: "<ng-container *ngIf=\"control?.valueChanges | async\" />\n\n<div\n class=\"t-ghost\"\n [attr.data-size]=\"size\"\n [style.--tui-slider-thumb-ratio]=\"ratio\"\n [style.inset-inline-start.px]=\"ghostStart\"\n [style.left.px]=\"ghostStart\"\n>\n <ng-content />\n</div>\n\n<ng-content select=\"input[type=range]\" />\n", styles: [":host{position:relative}.t-ghost{position:absolute;top:0;bottom:0;margin:auto;border-radius:50%;pointer-events:none}.t-ghost[data-size=s]{inline-size:.5rem;block-size:.5rem;transform:translate(calc(var(--tui-slider-thumb-ratio) * -.5rem * var(--tui-inline)))}.t-ghost[data-size=m]{inline-size:.75rem;block-size:.75rem;transform:translate(calc(var(--tui-slider-thumb-ratio) * -.75rem * var(--tui-inline)))}@supports (inset-inline-end: 0){:host-context([dir=\"rtl\"]) .t-ghost{left:unset!important}}\n"] }]
}], propDecorators: { slider: [{
type: ContentChild,
args: [TuiSliderComponent]
}], control: [{
type: ContentChild,
args: [NgControl]
}] } });
const TuiSlider = [
TuiSliderComponent,
TuiSliderThumbLabel,
TuiSliderKeyStepsBase,
TuiSliderKeySteps,
TuiSliderReadonly,
];
/**
* Generated bundle index. Do not edit.
*/
export { TUI_FLOATING_PRECISION, TUI_SLIDER_DEFAULT_OPTIONS, TUI_SLIDER_OPTIONS, TuiSlider, TuiSliderComponent, TuiSliderKeySteps, TuiSliderKeyStepsBase, TuiSliderReadonly, TuiSliderThumbLabel, tuiCreateKeyStepsTransformer, tuiKeyStepValueToPercentage, tuiPercentageToKeyStepValue, tuiSliderOptionsProvider };
//# sourceMappingURL=taiga-ui-kit-components-slider.mjs.map