UNPKG

@taiga-ui/kit

Version:
380 lines (375 loc) • 12.8 kB
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