Skip to content

Commit 59b38d1

Browse files
author
unknown
committed
1.0.0-beta3
1 parent d264635 commit 59b38d1

18 files changed

+1475
-404
lines changed

README.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MDB 5 Vue
22

3-
Version: FREE 1.0.0-beta2
3+
Version: FREE 1.0.0-beta3
44

55
Documentation:
66
https://mdbootstrap.com/docs/b5/vue/

css/mdb.min.css

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

css/mdb.min.css.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/mdb.common.js

Lines changed: 845 additions & 370 deletions
Large diffs are not rendered by default.

js/mdb.common.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/mdb.umd.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/mdb.umd.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mdb-vue-ui-kit",
3-
"version": "1.0.0-beta2",
3+
"version": "1.0.0-beta3",
44
"main": "js/mdb.umd.min.js",
55
"repository": "https://github.com/mdbootstrap/mdb-vue-ui-kit.git",
66
"author": "MDBootstrap",
Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,352 @@
1+
<template>
2+
<component
3+
:is="tag"
4+
:class="className"
5+
v-bind="$attrs"
6+
@mouseenter="handleMouseenter"
7+
@mouseleave="handleMouseleave"
8+
@keydown.right="handleRight"
9+
@keydown.left="handleLeft"
10+
@touchstart="handleTouchstart"
11+
@touchmove="handleTouchmove"
12+
@touchend="handleTouchend"
13+
>
14+
<div v-if="indicators" class="carousel-indicators">
15+
<button
16+
v-for="(item, key) in items"
17+
:key="key"
18+
type="button"
19+
:class="activeItemKey === key && 'active'"
20+
:aria-current="activeItemKey === key && 'true'"
21+
:aria-label="`Slide ${key + 1}`"
22+
@click="slideTo(key)"
23+
></button>
24+
</div>
25+
26+
<div class="carousel-inner" ref="carouselInnerRef">
27+
<div v-for="(item, key) in items" class="carousel-item" :key="key">
28+
<img :src="item.src" :alt="item.alt" :class="itemsClass" />
29+
<div v-if="item.label || item.caption" :class="captionsClass">
30+
<h5 v-if="item.label">{{ item.label }}</h5>
31+
<p v-if="item.caption">{{ item.caption }}</p>
32+
</div>
33+
</div>
34+
</div>
35+
36+
<button
37+
v-if="controls"
38+
@click="prev"
39+
class="carousel-control-prev"
40+
type="button"
41+
>
42+
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
43+
<span class="visually-hidden">Previous</span>
44+
</button>
45+
<button
46+
v-if="controls"
47+
@click="next"
48+
class="carousel-control-next"
49+
type="button"
50+
>
51+
<span class="carousel-control-next-icon" aria-hidden="true"></span>
52+
<span class="visually-hidden">Next</span>
53+
</button>
54+
</component>
55+
</template>
56+
57+
<script>
58+
import { computed, ref, onMounted, onUnmounted, watch } from "vue";
59+
60+
export default {
61+
name: "MDBCarousel",
62+
props: {
63+
captionsClass: {
64+
type: String,
65+
default: "carousel-caption d-none d-md-block"
66+
},
67+
controls: {
68+
type: Boolean,
69+
default: true
70+
},
71+
dark: Boolean,
72+
fade: Boolean,
73+
indicators: {
74+
type: Boolean,
75+
default: true
76+
},
77+
interval: {
78+
type: [Number, Boolean],
79+
default: 5000
80+
},
81+
items: {
82+
type: Array,
83+
reguired: true
84+
},
85+
itemsClass: {
86+
type: String,
87+
default: "d-block w-100"
88+
},
89+
keyboard: {
90+
type: Boolean,
91+
default: true
92+
},
93+
modelValue: {
94+
type: Number,
95+
default: 0
96+
},
97+
pause: {
98+
type: [String, Boolean],
99+
default: "hover"
100+
},
101+
tag: {
102+
type: String,
103+
default: "div"
104+
},
105+
touch: {
106+
type: Boolean,
107+
default: true
108+
}
109+
},
110+
emits: ["update:modelValue"],
111+
setup(props, { emit }) {
112+
const className = computed(() => {
113+
return [
114+
"carousel",
115+
"slide",
116+
props.fade && "carousel-fade",
117+
props.dark && "carousel-dark"
118+
];
119+
});
120+
121+
const activeItemKey = ref(props.modelValue);
122+
const carouselInnerRef = ref(null);
123+
const isSliding = ref(false);
124+
125+
let slidingInterval = null;
126+
let isPaused = false;
127+
128+
const prev = () => {
129+
slideTo("prev");
130+
};
131+
const next = () => {
132+
slideTo("next");
133+
};
134+
const slideTo = target => {
135+
if (isSliding.value) {
136+
return;
137+
}
138+
139+
const isPausedState = isPaused;
140+
isPaused = false;
141+
142+
slide(target);
143+
144+
isPaused = isPausedState;
145+
};
146+
147+
const slide = target => {
148+
if (isPaused || !carouselInnerRef.value) {
149+
return;
150+
}
151+
152+
isSliding.value = true;
153+
const targetItemKey = getTargetKey(target);
154+
const isNext = getTargetSlideOrder(target);
155+
const directionalClassName = getDirectionalClassName(isNext);
156+
const orderClassName = getOrderClassName(isNext);
157+
const currentItem = getItem(activeItemKey.value);
158+
const targetItem = getItem(targetItemKey);
159+
160+
activeItemKey.value = targetItemKey;
161+
targetItem.classList.add(orderClassName);
162+
emit("update:modelValue", activeItemKey.value);
163+
164+
if (props.interval) {
165+
reloadInterval();
166+
}
167+
168+
setTimeout(() => {
169+
currentItem.classList.add(directionalClassName);
170+
targetItem.classList.add(directionalClassName);
171+
}, 20);
172+
173+
setTimeout(() => {
174+
currentItem.classList.remove("active");
175+
currentItem.classList.remove(directionalClassName);
176+
targetItem.classList.remove(directionalClassName);
177+
targetItem.classList.remove(orderClassName);
178+
targetItem.classList.add("active");
179+
isSliding.value = false;
180+
}, 600);
181+
};
182+
183+
const getTargetKey = target => {
184+
if (target === "prev" && activeItemKey.value <= 0) {
185+
return props.items.length - 1;
186+
} else if (target === "prev") {
187+
return activeItemKey.value - 1;
188+
} else if (
189+
target === "next" &&
190+
activeItemKey.value >= props.items.length - 1
191+
) {
192+
return 0;
193+
} else if (target === "next") {
194+
return activeItemKey.value + 1;
195+
} else {
196+
return target;
197+
}
198+
};
199+
const getTargetSlideOrder = target => {
200+
if (target === "next" || target > activeItemKey.value) {
201+
return true;
202+
} else {
203+
return false;
204+
}
205+
};
206+
const getDirectionalClassName = isNext =>
207+
isNext ? "carousel-item-start" : "carousel-item-end";
208+
const getOrderClassName = isNext =>
209+
isNext ? "carousel-item-next" : "carousel-item-prev";
210+
const getItem = key =>
211+
carouselInnerRef.value.querySelectorAll(".carousel-item")[key];
212+
213+
const reloadInterval = () => {
214+
clearInterval(slidingInterval);
215+
slidingInterval = null;
216+
217+
const itemInterval =
218+
props.items[activeItemKey.value].interval || props.interval;
219+
slidingInterval = setInterval(() => {
220+
slide("next");
221+
}, itemInterval);
222+
};
223+
224+
// keyboard accessibility
225+
const handleMouseenter = () => {
226+
if (props.pause === "hover" && props.interval) {
227+
clearInterval(slidingInterval);
228+
slidingInterval = null;
229+
isPaused = true;
230+
}
231+
};
232+
const handleMouseleave = () => {
233+
if (props.pause === "hover" && props.interval) {
234+
reloadInterval();
235+
isPaused = false;
236+
}
237+
};
238+
const handleRight = () => {
239+
if (props.keyboard) {
240+
next();
241+
}
242+
};
243+
const handleLeft = () => {
244+
if (props.keyboard) {
245+
prev();
246+
}
247+
};
248+
249+
// touch events
250+
const pointerEvent = Boolean(window.PointerEvent);
251+
const touchStartX = ref(0);
252+
const touchDeltaX = ref(0);
253+
const handleTouchstart = event => {
254+
if (!props.touch) {
255+
return;
256+
}
257+
258+
if (
259+
pointerEvent &&
260+
(event.pointerType === "pen" || event.pointerType === "touch")
261+
) {
262+
touchStartX.value = event.clientX;
263+
} else {
264+
touchStartX.value = event.touches[0].clientX;
265+
}
266+
};
267+
const handleTouchmove = event => {
268+
if (!props.touch) {
269+
return;
270+
}
271+
272+
touchDeltaX.value =
273+
event.touches && event.touches.length > 1
274+
? 0
275+
: event.touches[0].clientX - touchStartX.value;
276+
};
277+
const handleTouchend = event => {
278+
if (!props.touch) {
279+
return;
280+
}
281+
282+
if (
283+
pointerEvent &&
284+
(event.pointerType === "pen" || event.pointerType === "touch")
285+
) {
286+
touchDeltaX.value = event.clientX - touchStartX.value;
287+
}
288+
289+
handleSwipe();
290+
};
291+
const handleSwipe = () => {
292+
const absDeltax = Math.abs(touchDeltaX.value);
293+
294+
if (absDeltax <= 40) {
295+
return;
296+
}
297+
298+
const direction = absDeltax / touchDeltaX.value;
299+
touchDeltaX.value = 0;
300+
301+
if (!direction) {
302+
return;
303+
}
304+
305+
if (direction > 0) {
306+
prev();
307+
} else {
308+
next();
309+
}
310+
};
311+
312+
onMounted(() => {
313+
const currentActiveItem = carouselInnerRef.value.querySelectorAll(
314+
".carousel-item"
315+
)[activeItemKey.value];
316+
currentActiveItem.classList.add("active");
317+
318+
if (props.interval) {
319+
reloadInterval();
320+
}
321+
});
322+
323+
onUnmounted(() => {
324+
if (props.interval) {
325+
clearInterval(slidingInterval);
326+
slidingInterval = null;
327+
}
328+
});
329+
330+
watch(
331+
() => props.modelValue,
332+
targetItemKey => slideTo(targetItemKey)
333+
);
334+
335+
return {
336+
className,
337+
carouselInnerRef,
338+
activeItemKey,
339+
handleMouseenter,
340+
handleMouseleave,
341+
handleRight,
342+
handleLeft,
343+
handleTouchstart,
344+
handleTouchmove,
345+
handleTouchend,
346+
slideTo,
347+
next,
348+
prev
349+
};
350+
}
351+
};
352+
</script>

0 commit comments

Comments
 (0)