UNPKG

4.64 kBJavaScriptView Raw
1import {translate} from '../../mixin/internal/slideshow-animations';
2import {clamp, createEvent, css, Deferred, includes, index, isRtl, noop, position, sortBy, toNodes, Transition, trigger} from 'uikit-util';
3
4export default function (prev, next, dir, {center, easing, list}) {
5
6 const deferred = new Deferred();
7
8 const from = prev
9 ? getLeft(prev, list, center)
10 : getLeft(next, list, center) + bounds(next).width * dir;
11 const to = next
12 ? getLeft(next, list, center)
13 : from + bounds(prev).width * dir * (isRtl ? -1 : 1);
14
15 return {
16
17 dir,
18
19 show(duration, percent = 0, linear) {
20
21 const timing = linear ? 'linear' : easing;
22 duration -= Math.round(duration * clamp(percent, -1, 1));
23
24 this.translate(percent);
25
26 prev && this.updateTranslates();
27 percent = prev ? percent : clamp(percent, 0, 1);
28 triggerUpdate(this.getItemIn(), 'itemin', {percent, duration, timing, dir});
29 prev && triggerUpdate(this.getItemIn(true), 'itemout', {percent: 1 - percent, duration, timing, dir});
30
31 Transition
32 .start(list, {transform: translate(-to * (isRtl ? -1 : 1), 'px')}, duration, timing)
33 .then(deferred.resolve, noop);
34
35 return deferred.promise;
36
37 },
38
39 stop() {
40 return Transition.stop(list);
41 },
42
43 cancel() {
44 Transition.cancel(list);
45 },
46
47 reset() {
48 css(list, 'transform', '');
49 },
50
51 forward(duration, percent = this.percent()) {
52 Transition.cancel(list);
53 return this.show(duration, percent, true);
54 },
55
56 translate(percent) {
57
58 const distance = this.getDistance() * dir * (isRtl ? -1 : 1);
59
60 css(list, 'transform', translate(clamp(
61 -to + (distance - distance * percent),
62 -getWidth(list),
63 bounds(list).width
64 ) * (isRtl ? -1 : 1), 'px'));
65
66 this.updateTranslates();
67
68 if (prev) {
69 percent = clamp(percent, -1, 1);
70 triggerUpdate(this.getItemIn(), 'itemtranslatein', {percent, dir});
71 triggerUpdate(this.getItemIn(true), 'itemtranslateout', {percent: 1 - percent, dir});
72 }
73
74 },
75
76 percent() {
77 return Math.abs((css(list, 'transform').split(',')[4] * (isRtl ? -1 : 1) + from) / (to - from));
78 },
79
80 getDistance() {
81 return Math.abs(to - from);
82 },
83
84 getItemIn(out = false) {
85
86 const actives = this.getActives();
87 const all = sortBy(slides(list), 'offsetLeft');
88 const i = index(all, actives[dir * (out ? -1 : 1) > 0 ? actives.length - 1 : 0]);
89
90 return ~i && all[i + (prev && !out ? dir : 0)];
91
92 },
93
94 getActives() {
95
96 const left = getLeft(prev || next, list, center);
97
98 return sortBy(slides(list).filter(slide => {
99 const slideLeft = getElLeft(slide, list);
100 return slideLeft >= left && slideLeft + bounds(slide).width <= bounds(list).width + left;
101 }), 'offsetLeft');
102
103 },
104
105 updateTranslates() {
106
107 const actives = this.getActives();
108
109 slides(list).forEach(slide => {
110 const isActive = includes(actives, slide);
111
112 triggerUpdate(slide, `itemtranslate${isActive ? 'in' : 'out'}`, {
113 percent: isActive ? 1 : 0,
114 dir: slide.offsetLeft <= next.offsetLeft ? 1 : -1
115 });
116 });
117 }
118
119 };
120
121}
122
123function getLeft(el, list, center) {
124
125 const left = getElLeft(el, list);
126
127 return center
128 ? left - centerEl(el, list)
129 : Math.min(left, getMax(list));
130
131}
132
133export function getMax(list) {
134 return Math.max(0, getWidth(list) - bounds(list).width);
135}
136
137export function getWidth(list) {
138 return slides(list).reduce((right, el) => bounds(el).width + right, 0);
139}
140
141export function getMaxWidth(list) {
142 return slides(list).reduce((right, el) => Math.max(right, bounds(el).width), 0);
143}
144
145function centerEl(el, list) {
146 return bounds(list).width / 2 - bounds(el).width / 2;
147}
148
149export function getElLeft(el, list) {
150 return (position(el).left + (isRtl ? bounds(el).width - bounds(list).width : 0)) * (isRtl ? -1 : 1);
151}
152
153export function bounds(el) {
154 return el.getBoundingClientRect();
155}
156
157function triggerUpdate(el, type, data) {
158 trigger(el, createEvent(type, false, false, data));
159}
160
161function slides(list) {
162 return toNodes(list.children);
163}