@exadel/esl
Version:
Exadel Smart Library (ESL) is the lightweight custom elements library that provide a set of super-flexible components
148 lines (147 loc) • 6.52 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var ESLCarouselTouchMixin_1;
import { ExportNs } from '../../../esl-utils/environment/export-ns';
import { listen } from '../../../esl-utils/decorators';
import { getParentScrollOffsets, isOffsetChanged } from '../../../esl-utils/dom/scroll';
import { ESLCarouselPlugin } from '../esl-carousel.plugin';
/**
* {@link ESLCarousel} Touch handler mixin
*
* Usage:
* ```
* <esl-carousel esl-carousel-touch></esl-carousel>
*
* <esl-carousel esl-carousel-touch="@XS => swipe | @+SM => drag"></esl-carousel>
* ```
*/
let ESLCarouselTouchMixin = ESLCarouselTouchMixin_1 = class ESLCarouselTouchMixin extends ESLCarouselPlugin {
/** @returns whether the swipe mode is active */
get isSwipeMode() {
return this.config.type === ESLCarouselTouchMixin_1.SWIPE_TYPE;
}
/** @returns whether the drag mode is active */
get isDragMode() {
return this.config.type === ESLCarouselTouchMixin_1.DRAG_TYPE;
}
/** @returns whether the free mode is active */
get isFreeMode() {
return this.config.type === ESLCarouselTouchMixin_1.FREE_TYPE;
}
/** @returns whether the plugin is disabled (due to carousel state or plugin config) */
get isDisabled() {
// Plugin is disabled
if (!this.isDragMode && !this.isSwipeMode && !this.isFreeMode)
return true;
// Carousel is not ready
if (!this.$host.renderer || this.$host.animating)
return true;
// No nav required
return this.$host.size <= this.$host.config.count;
}
/** @returns whether the drugging is prevented by external conditions (scroll, selection) */
get isPrevented() {
var _a;
// Prevents draggable state if the content is scrolled
if (isOffsetChanged(this.startScrollOffsets))
return true;
// Prevents draggable state if the text is selected
return ((_a = document.getSelection()) === null || _a === void 0 ? void 0 : _a.isCollapsed) === false;
}
/** @returns offset between start point and passed event point */
getOffset(event) {
if (event.type === 'pointercancel')
return 0;
const property = this.$host.config.vertical ? 'clientY' : 'clientX';
return this.startOffset + (this.startEvent ? (event[property] - this.startEvent[property]) : 0);
}
/** @returns if the passed event leads to swipe action */
isSwipeAccepted(event) {
if (!this.startEvent)
return false;
// Ignore swipe if timeout threshold exceeded
if (event.timeStamp - this.startEvent.timeStamp > this.config.swipeTimeout)
return false;
// Ignore swipe if offset is not enough
return Math.abs(this.getOffset(event)) > this.config.swipeDistance;
}
/** Handles `mousedown` / `touchstart` event to manage thumb drag start and scroll clicks */
_onPointerDown(event) {
if (this.isDisabled)
return;
this.startEvent = event;
this.startIndex = this.$host.activeIndex;
this.startOffset = this.$host.offset;
this.startScrollOffsets = getParentScrollOffsets(event.target, this.$host);
this.$$on({ group: 'pointer' });
}
/** Processes `mousemove` and `touchmove` events. */
_onPointerMove(event) {
const offset = this.getOffset(event);
if (!this.$host.hasAttribute('dragging')) {
// Stop tracking if prevented before dragging started
if (this.isPrevented)
return this._onPointerUp(event);
// Does not start dragging mode if offset have not reached tolerance
if (Math.abs(offset) < this.config.tolerance)
return;
this.$$attr('dragging', true);
}
this.$host.setPointerCapture(event.pointerId);
if (this.isDragMode || this.isFreeMode) {
this.$host.move(offset, this.startIndex, { activator: this });
}
}
/** Processes `mouseup` and `touchend` events. */
_onPointerUp(event) {
// Unbinds drag listeners
this.$$off({ group: 'pointer' });
if (this.$host.hasPointerCapture(event.pointerId)) {
this.$host.releasePointerCapture(event.pointerId);
}
if (this.$$attr('dragging', false) === null)
return;
const offset = this.getOffset(event);
// Commit drag offset (should be commited to 0 if the event is canceled)
if (this.isDragMode) {
this.$host.move(offset, this.startIndex, { activator: this });
this.$host.commit({ activator: this }).catch(console.debug);
}
// Swipe final check
if (this.isSwipeMode && offset && !this.isPrevented && this.isSwipeAccepted(event)) {
const target = `${this.config.swipeType}:${offset < 0 ? 'next' : 'prev'}`;
if (!this.$host.canNavigate(target))
return;
this.$host.goTo(target, { activator: this }).catch(console.debug);
}
}
};
ESLCarouselTouchMixin.is = 'esl-carousel-touch';
ESLCarouselTouchMixin.DRAG_TYPE = 'drag';
ESLCarouselTouchMixin.FREE_TYPE = 'free';
ESLCarouselTouchMixin.SWIPE_TYPE = 'swipe';
ESLCarouselTouchMixin.DEFAULT_CONFIG_KEY = 'type';
ESLCarouselTouchMixin.DEFAULT_CONFIG = {
tolerance: 10,
type: 'drag',
swipeType: 'group',
swipeDistance: 20,
swipeTimeout: 400
};
__decorate([
listen('pointerdown')
], ESLCarouselTouchMixin.prototype, "_onPointerDown", null);
__decorate([
listen({ auto: false, event: 'pointermove', group: 'pointer' })
], ESLCarouselTouchMixin.prototype, "_onPointerMove", null);
__decorate([
listen({ auto: false, event: 'pointerup pointercancel', group: 'pointer' })
], ESLCarouselTouchMixin.prototype, "_onPointerUp", null);
ESLCarouselTouchMixin = ESLCarouselTouchMixin_1 = __decorate([
ExportNs('Carousel.Touch')
], ESLCarouselTouchMixin);
export { ESLCarouselTouchMixin };