@taiga-ui/kit
Version:
Taiga UI Angular main components kit
380 lines (375 loc) • 12.8 kB
JavaScript
import { __decorate, __param } from 'tslib';
import { Input, HostBinding, Directive, ChangeDetectorRef, Inject, ViewChild } from '@angular/core';
import { AbstractTuiControl, clamp, round, tuiDefaultProp, typedFromEvent, setNativeFocused, quantize } from '@taiga-ui/cdk';
import { tuiCreateNumberMask, tuiCreateAutoCorrectedNumberPipe, maskedNumberStringToNumber } from '@taiga-ui/core';
import { TUI_FLOATING_PRECISION } from '@taiga-ui/kit/constants';
import { NgControl } from '@angular/forms';
import { TUI_FROM_TO_TEXTS } from '@taiga-ui/kit/tokens';
import { Subject, race, Observable } from 'rxjs';
import { map, switchMap, takeUntil } from 'rxjs/operators';
function quantumAssertion(quantum) {
return quantum > 0;
}
/**
* @internal
*/
let AbstractTuiInputSlider = class AbstractTuiInputSlider extends AbstractTuiControl {
constructor() {
super(...arguments);
this.min = 0;
this.max = Infinity;
this.minLabel = '';
this.maxLabel = '';
this.pluralize = null;
this.segmentsPluralize = null;
this.segments = 0;
this.steps = 0;
this.quantum = 1;
this.keySteps = null;
this.size = 'l';
this.mask = (quantum, min) => ({
mask: tuiCreateNumberMask({
allowNegative: min < 0,
allowDecimal: !Number.isInteger(quantum),
}),
pipe: tuiCreateAutoCorrectedNumberPipe(),
guide: false,
});
}
get segmented() {
return this.segments > 0;
}
get hasPlaceholder() {
return this.size === 'l';
}
get inputMode() {
return Number.isInteger(this.quantum)
? "numeric" /* Numeric */
: "decimal" /* Decimal */;
}
get length() {
return this.max - this.min;
}
get computedSteps() {
return this.steps || this.length / this.quantum;
}
get step() {
return this.length / this.computedSteps;
}
get hostMode() {
return this.modeDirective && this.modeDirective.mode;
}
onHovered(hovered) {
this.updateHovered(hovered);
}
isPluralized(pluralize) {
return pluralize !== null && pluralize.length === 3;
}
valueGuard(value) {
return this.quantum
? clamp(round(Math.round(value / this.quantum) * this.quantum, TUI_FLOATING_PRECISION), this.min, this.max)
: clamp(value, this.min, this.max);
}
capInputValue(value, max = this.max) {
const capped = Math.min(maskedNumberStringToNumber(value), max);
if (this.min < 0 && capped < this.min) {
return this.min;
}
return isNaN(capped) || capped < this.min ? null : capped;
}
};
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "min", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "max", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "minLabel", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "maxLabel", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "pluralize", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "segmentsPluralize", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "segments", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "steps", void 0);
__decorate([
Input(),
tuiDefaultProp(quantumAssertion, 'Quantum must be positive')
], AbstractTuiInputSlider.prototype, "quantum", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiInputSlider.prototype, "keySteps", void 0);
__decorate([
Input(),
HostBinding('attr.data-tui-host-size')
], AbstractTuiInputSlider.prototype, "size", void 0);
__decorate([
HostBinding('class._segmented')
], AbstractTuiInputSlider.prototype, "segmented", null);
__decorate([
HostBinding('attr.data-mode')
], AbstractTuiInputSlider.prototype, "hostMode", null);
AbstractTuiInputSlider = __decorate([
Directive()
], AbstractTuiInputSlider);
const SLIDER_KEYBOARD_STEP = 0.05;
const DOT_WIDTH = {
s: 8,
m: 16,
};
/**
* @awful TODO: refactor
* @internal
* @dynamic
*/
let AbstractTuiSlider = class AbstractTuiSlider extends AbstractTuiControl {
constructor(ngControl, changeDetectorRef, documentRef, fromToTexts$) {
super(ngControl, changeDetectorRef);
this.documentRef = documentRef;
this.fromToTexts$ = fromToTexts$;
this.min = 0;
this.max = Infinity;
this.segments = 0;
this.steps = 0;
this.pluralize = null;
this.size = 'm';
this.keySteps = null;
this.focusVisibleLeft = false;
this.focusVisibleRight = false;
// @bad TODO: handle pointer events instead of mouse and touch events
this.pointerDown$ = new Subject();
}
get segmented() {
return this.segments > 0;
}
get discrete() {
return this.steps > 0;
}
get length() {
return this.max - this.min;
}
get isLeftFocusable() {
return !this.disabled && this.focusable && this.right !== 100;
}
get isRightFocusable() {
return !this.disabled && this.focusable && this.left !== 100;
}
ngOnInit() {
super.ngOnInit();
const mouseMoves$ = typedFromEvent(this.documentRef, 'mousemove');
const mouseUps$ = typedFromEvent(this.documentRef, 'mouseup');
const touchMoves$ = typedFromEvent(this.documentRef, 'touchmove');
const touchEnds$ = typedFromEvent(this.documentRef, 'touchend');
let isPointerDownRight;
this.pointerDown$
.pipe(map((event) => {
const rect = event.currentTarget.getBoundingClientRect();
const clientX = event instanceof MouseEvent
? event.clientX
: event.touches[0].clientX;
const fraction = clamp(this.getFractionFromEvents(rect, clientX), 0, 1);
const deltaLeft = fraction * 100 - this.left;
const deltaRight = fraction * 100 - 100 + this.right;
isPointerDownRight =
Math.abs(deltaLeft) > Math.abs(deltaRight) ||
deltaRight > 0 ||
(this.left === 0 && this.right === 100);
const calibratedFraction = clamp(this.getCalibratedFractionFromEvents(rect, clientX, isPointerDownRight), 0, 1);
const value = this.getValueFromFraction(this.fractionGuard(calibratedFraction));
this.processValue(value, isPointerDownRight);
this.processFocus(isPointerDownRight);
return rect;
}), switchMap(rect => race([touchMoves$, mouseMoves$]).pipe(map((event) => this.getCalibratedFractionFromEvents(rect, event instanceof MouseEvent
? event.clientX
: event.touches[0].clientX, isPointerDownRight)), takeUntil(race([mouseUps$, touchEnds$])))), map(fraction => this.fractionGuard(fraction)))
.subscribe(fraction => {
this.processValue(this.getValueFromFraction(fraction), isPointerDownRight);
});
}
ngOnDestroy() {
super.ngOnDestroy();
this.pointerDown$.complete();
}
onMouseDown(event) {
if (this.disabled) {
return;
}
event.preventDefault();
this.pointerDown$.next(event);
}
onTouchStart(event) {
if (this.disabled) {
return;
}
event.preventDefault();
this.pointerDown$.next(event);
}
isPluralized(pluralize) {
return pluralize !== null && pluralize.length === 3;
}
decrement(right) {
this.processStep(false, right);
}
increment(right) {
this.processStep(true, right);
}
getSegmentLabel(segment) {
return round(this.getValueFromFraction(segment / this.segments), 2);
}
getSegmentPrefix(segment, texts) {
if (this.segments !== 1) {
return '';
}
if (segment === 0) {
return `${texts[0]} `;
}
return `${texts[1]} `;
}
onActiveZone(active) {
this.updateFocused(active);
}
onLeftFocusVisible(focusVisible) {
this.focusVisibleLeft = focusVisible;
}
onRightFocusVisible(focusVisible) {
this.focusVisibleRight = focusVisible;
}
getFractionFromValue(value) {
const fraction = (value - this.min) / this.length;
return this.keySteps !== null
? this.fractionValueKeyStepConverter(value, false)
: clamp(Number.isFinite(fraction) ? fraction : 1, 0, 1);
}
getValueFromFraction(fraction) {
return this.keySteps !== null
? this.fractionValueKeyStepConverter(fraction, true)
: round(this.fractionGuard(fraction) * this.length + this.min, TUI_FLOATING_PRECISION);
}
getCalibratedFractionFromEvents(rect, clientX, _) {
return this.getFractionFromEvents(rect, clientX);
}
processFocus(right) {
if (!this.focusable || !this.dotRight || !this.dotLeft) {
return;
}
if (right) {
setNativeFocused(this.dotRight.nativeElement);
}
else {
setNativeFocused(this.dotLeft.nativeElement);
}
}
/**
* Function for converting the fullness of the slider to a value and vice versa
* taking into account the steps of linear dependence.
*
* @param value passed value
* @param isFraction translation is carried out from fullness to value
*/
fractionValueKeyStepConverter(value, isFraction) {
const steps = [[0, this.min]].concat(this.keySteps, [
[100, this.max],
]);
let prevFraction = 0;
let nextFraction = 100;
let prevValue = this.min;
let nextValue = this.max;
for (let i = 1; i < steps.length; i++) {
if ((isFraction && steps[i][0] / 100 > value) ||
(!isFraction && steps[i][1] > value)) {
prevFraction = steps[i - 1][0] || 0;
nextFraction = steps[i][0];
prevValue = steps[i - 1][1];
nextValue = steps[i][1];
break;
}
}
const deltaFraction = nextFraction - prevFraction;
const deltaValue = nextValue - prevValue;
return isFraction
? round(((value * 100 - prevFraction) / deltaFraction) * deltaValue + prevValue, TUI_FLOATING_PRECISION)
: clamp(((value - prevValue) / deltaValue) * deltaFraction + prevFraction, 0, 100) / 100;
}
fractionGuard(fraction) {
return this.discrete
? clamp(quantize(fraction, 1 / this.steps), 0, 1)
: clamp(fraction, 0, 1);
}
getFractionFromEvents(rect, clientX) {
const value = clientX - rect.left - DOT_WIDTH[this.size] / 2;
const total = rect.width - DOT_WIDTH[this.size];
return round(value / total, TUI_FLOATING_PRECISION);
}
};
AbstractTuiSlider.ctorParameters = () => [
{ type: NgControl },
{ type: ChangeDetectorRef },
{ type: Document },
{ type: Observable, decorators: [{ type: Inject, args: [TUI_FROM_TO_TEXTS,] }] }
];
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "min", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "max", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "segments", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "steps", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "pluralize", void 0);
__decorate([
Input(),
HostBinding('attr.data-tui-host-size'),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "size", void 0);
__decorate([
Input(),
tuiDefaultProp()
], AbstractTuiSlider.prototype, "keySteps", void 0);
__decorate([
ViewChild('dotLeft')
], AbstractTuiSlider.prototype, "dotLeft", void 0);
__decorate([
ViewChild('dotRight')
], AbstractTuiSlider.prototype, "dotRight", void 0);
__decorate([
HostBinding('class._segmented')
], AbstractTuiSlider.prototype, "segmented", null);
AbstractTuiSlider = __decorate([
Directive(),
__param(3, Inject(TUI_FROM_TO_TEXTS))
], AbstractTuiSlider);
/**
* Generated bundle index. Do not edit.
*/
export { AbstractTuiInputSlider, AbstractTuiSlider, DOT_WIDTH, SLIDER_KEYBOARD_STEP, quantumAssertion };
//# sourceMappingURL=taiga-ui-kit-abstract.js.map