UNPKG

uikit

Version:

UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.

160 lines (113 loc) 4.75 kB
import {translate} from '../../mixin/internal/slideshow-animations'; import {children, clamp, createEvent, css, Deferred, dimensions, findIndex, includes, isRtl, noop, position, Transition, trigger} from 'uikit-util'; export default function (prev, next, dir, {center, easing, list}) { const deferred = new Deferred(); const from = prev ? getLeft(prev, list, center) : getLeft(next, list, center) + dimensions(next).width * dir; const to = next ? getLeft(next, list, center) : from + dimensions(prev).width * dir * (isRtl ? -1 : 1); return { dir, show(duration, percent = 0, linear) { const timing = linear ? 'linear' : easing; duration -= Math.round(duration * clamp(percent, -1, 1)); this.translate(percent); percent = prev ? percent : clamp(percent, 0, 1); triggerUpdate(this.getItemIn(), 'itemin', {percent, duration, timing, dir}); prev && triggerUpdate(this.getItemIn(true), 'itemout', {percent: 1 - percent, duration, timing, dir}); Transition .start(list, {transform: translate(-to * (isRtl ? -1 : 1), 'px')}, duration, timing) .then(deferred.resolve, noop); return deferred.promise; }, cancel() { Transition.cancel(list); }, reset() { css(list, 'transform', ''); }, forward(duration, percent = this.percent()) { Transition.cancel(list); return this.show(duration, percent, true); }, translate(percent) { const distance = this.getDistance() * dir * (isRtl ? -1 : 1); css(list, 'transform', translate(clamp( -to + (distance - distance * percent), -getWidth(list), dimensions(list).width ) * (isRtl ? -1 : 1), 'px')); const actives = this.getActives(); const itemIn = this.getItemIn(); const itemOut = this.getItemIn(true); percent = prev ? clamp(percent, -1, 1) : 0; children(list).forEach((slide, i) => { const isActive = includes(actives, slide); const isIn = slide === itemIn; const isOut = slide === itemOut; const translateIn = isIn || !isOut && (isActive || dir * (isRtl ? -1 : 1) === -1 ^ getElLeft(slide, list) > getElLeft(prev || next)); triggerUpdate(slide, `itemtranslate${translateIn ? 'in' : 'out'}`, { dir, percent: isOut ? 1 - percent : isIn ? percent : isActive ? 1 : 0 }); }); }, percent() { return Math.abs((css(list, 'transform').split(',')[4] * (isRtl ? -1 : 1) + from) / (to - from)); }, getDistance() { return Math.abs(to - from); }, getItemIn(out = false) { let actives = this.getActives(); let nextActives = inView(list, getLeft(next || prev, list, center)); if (out) { const temp = actives; actives = nextActives; nextActives = temp; } return nextActives[findIndex(nextActives, el => !includes(actives, el))]; }, getActives() { return inView(list, getLeft(prev || next, list, center)); } }; } function getLeft(el, list, center) { const left = getElLeft(el, list); return center ? left - centerEl(el, list) : Math.min(left, getMax(list)); } export function getMax(list) { return Math.max(0, getWidth(list) - dimensions(list).width); } export function getWidth(list) { return children(list).reduce((right, el) => dimensions(el).width + right, 0); } function centerEl(el, list) { return dimensions(list).width / 2 - dimensions(el).width / 2; } export function getElLeft(el, list) { return el && (position(el).left + (isRtl ? dimensions(el).width - dimensions(list).width : 0)) * (isRtl ? -1 : 1) || 0; } function inView(list, listLeft) { listLeft -= 1; const listRight = listLeft + dimensions(list).width + 2; return children(list).filter(slide => { const slideLeft = getElLeft(slide, list); const slideRight = slideLeft + dimensions(slide).width; return slideLeft >= listLeft && slideRight <= listRight; }); } function triggerUpdate(el, type, data) { trigger(el, createEvent(type, false, false, data)); }