Skip to content

Commit 0cd1b47

Browse files
authored
Merge pull request #464 from ismail9k/add-fade-animation
Add fade in-out animation effect to carousel
2 parents fda8f41 + 3f4e15c commit 0cd1b47

File tree

7 files changed

+77
-11
lines changed

7 files changed

+77
-11
lines changed

playground/App.vue

+14-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ import {
88
} from '@/index'
99
import { computed, onMounted, reactive, ref } from 'vue'
1010
11-
import { DIR_MAP, SNAP_ALIGN_OPTIONS, BREAKPOINT_MODE_OPTIONS } from '@/shared/constants'
11+
import {
12+
DIR_MAP,
13+
SNAP_ALIGN_OPTIONS,
14+
BREAKPOINT_MODE_OPTIONS,
15+
SLIDE_EFFECTS,
16+
} from '@/shared/constants'
1217
1318
const carouselWrapper = ref<HTMLDivElement | null>(null)
1419
const carousel = ref<VueCarousel | null>(null)
@@ -30,6 +35,7 @@ const defaultSlides = [
3035
const defaultConfig = {
3136
currentSlide: 0,
3237
snapAlign: 'center',
38+
slideEffect: 'slide',
3339
itemsToScroll: 1,
3440
itemsToShow: 2,
3541
autoplay: null,
@@ -93,6 +99,12 @@ const formFields = [
9399
path: 'snapAlign',
94100
options: SNAP_ALIGN_OPTIONS,
95101
},
102+
{
103+
type: 'select',
104+
label: 'Slide Effect',
105+
path: 'slideEffect',
106+
options: SLIDE_EFFECTS,
107+
},
96108
{
97109
type: 'select',
98110
label: 'Direction',
@@ -141,6 +153,7 @@ const formFields = [
141153
]
142154
143155
const handleReset = () => {
156+
return
144157
// Reset animation
145158
if (carouselWrapper.value) {
146159
carouselWrapper.value.classList.remove('pop-in')

src/components/Carousel/Carousel.css

+25
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
position: relative;
2222
transition: transform ease-out;
2323
height: var(--vc-trk-height, auto);
24+
transition-duration: var(--vc-trk-transition-duration);
2425
}
2526

2627
.carousel__viewport {
@@ -61,3 +62,27 @@
6162
margin-inline-start: var(--vc-trk-cloned-offset);
6263
}
6364
}
65+
66+
.carousel.is-effect-fade {
67+
.carousel__track {
68+
transition: none;
69+
display: grid;
70+
grid-template-columns: 100%;
71+
grid-template-rows: 100%;
72+
}
73+
74+
.carousel__slide {
75+
opacity: 0;
76+
width: 100% !important;
77+
height: 100% !important;
78+
transition: opacity ease-in-out;
79+
transition-duration: var(--vc-trk-transition-duration);
80+
grid-area: 1 / 1; /* Make all slides occupy the same grid cell */
81+
pointer-events: none; /* Prevent inactive slides from being clickable */
82+
}
83+
84+
.carousel__slide--active {
85+
opacity: 1;
86+
pointer-events: auto; /* Re-enable pointer events for active slide */
87+
}
88+
}

src/components/Carousel/Carousel.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -697,9 +697,11 @@ export const Carousel = defineComponent({
697697
})
698698

699699
const trackStyle = computed(() => ({
700-
transform: trackTransform.value,
701-
'transition-duration': isSliding.value ? `${config.transition}ms` : undefined,
700+
transform: config.slideEffect === 'slide' ? trackTransform.value : undefined,
702701
gap: config.gap > 0 ? `${config.gap}px` : undefined,
702+
'--vc-trk-transition-duration': isSliding.value
703+
? `${config.transition}ms`
704+
: undefined,
703705
'--vc-trk-height': trackHeight.value,
704706
'--vc-trk-cloned-offset': `${clonedSlidesOffset.value}px`,
705707
}))
@@ -755,6 +757,7 @@ export const Carousel = defineComponent({
755757
class: [
756758
'carousel',
757759
`is-${normalizedDir.value}`,
760+
`is-effect-${config.slideEffect}`,
758761
{
759762
'is-vertical': isVertical.value,
760763
'is-sliding': isSliding.value,

src/components/Carousel/carouselProps.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,17 @@ import {
44
BREAKPOINT_MODE_OPTIONS,
55
DEFAULT_CONFIG,
66
DIR_OPTIONS,
7+
SLIDE_EFFECTS,
78
SNAP_ALIGN_OPTIONS,
89
} from '@/shared'
910

10-
import type { BreakpointMode, Dir, SnapAlign, CarouselConfig } from '@/shared'
11+
import type {
12+
BreakpointMode,
13+
Dir,
14+
SnapAlign,
15+
CarouselConfig,
16+
SlideEffect,
17+
} from '@/shared'
1118

1219
export const carouselProps = {
1320
// enable/disable the carousel component
@@ -106,5 +113,12 @@ export const carouselProps = {
106113
ignoreAnimations: {
107114
default: false,
108115
type: [Array, Boolean, String] as PropType<CarouselConfig['ignoreAnimations']>,
109-
}
116+
},
117+
slideEffect: {
118+
type: String as PropType<SlideEffect>,
119+
default: DEFAULT_CONFIG.slideEffect,
120+
validator(value: SlideEffect) {
121+
return SLIDE_EFFECTS.includes(value)
122+
},
123+
},
110124
}

src/shared/constants.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { CarouselConfig } from './types'
22

3-
export const SNAP_ALIGN_OPTIONS = ['center', 'start', 'end', 'center-even', 'center-odd'] as const
3+
export const SNAP_ALIGN_OPTIONS = [
4+
'center',
5+
'start',
6+
'end',
7+
'center-even',
8+
'center-odd',
9+
] as const
10+
export const SLIDE_EFFECTS = ['slide', 'fade'] as const
411
export const BREAKPOINT_MODE_OPTIONS = ['viewport', 'carousel'] as const
512
export const DIR_OPTIONS = [
613
'ltr',
@@ -53,4 +60,5 @@ export const DEFAULT_CONFIG: CarouselConfig = {
5360
breakpoints: undefined,
5461
i18n: I18N_DEFAULT_CONFIG,
5562
ignoreAnimations: false,
63+
slideEffect: SLIDE_EFFECTS[0],
5664
}

src/shared/types.ts

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
I18N_DEFAULT_CONFIG,
66
NORMALIZED_DIR_OPTIONS,
77
DIR_MAP,
8+
SLIDE_EFFECTS,
89
} from './constants'
910

1011
export type Breakpoints = {
@@ -13,6 +14,7 @@ export type Breakpoints = {
1314
>
1415
}
1516

17+
export type SlideEffect = (typeof SLIDE_EFFECTS)[number]
1618
export type SnapAlign = (typeof SNAP_ALIGN_OPTIONS)[number]
1719

1820
export type Dir = (typeof DIR_OPTIONS)[number]
@@ -44,6 +46,7 @@ export interface CarouselConfig {
4446
height: string | number
4547
i18n: { [key in I18nKeys]?: string }
4648
ignoreAnimations: boolean | string[] | string
49+
slideEffect: SlideEffect
4750
}
4851

4952
export type VueClass = string | Record<string, boolean> | VueClass[]

tests/integration/__snapshots__/carousel.spec.ts.snap

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`SSR Carousel > renders server side properly 1`] = `
44
"<div id="app">
5-
<section class="carousel is-ltr" dir="ltr" aria-label="Gallery" tabindex="0">
5+
<section class="carousel is-ltr is-effect-slide" dir="ltr" aria-label="Gallery" tabindex="0">
66
<div class="carousel__viewport">
77
<ol class="carousel__track" style="transform: translateX(0px); --vc-trk-cloned-offset: 0px;">
88
<li style="width: 50%;" class="carousel__slide carousel__slide--clone" aria-hidden="true">5 <input type="text" tabindex="-1"></li>
@@ -31,11 +31,11 @@ exports[`SSR Carousel > renders server side properly 1`] = `
3131
</div>"
3232
`;
3333
34-
exports[`SSR Carousel > renders server side properly 2`] = `"<div id="app"><section class="carousel is-ltr" dir="ltr" aria-label="Gallery" tabindex="0"><div class="carousel__viewport"><ol class="carousel__track" style="transform:translateX(0px);--vc-trk-cloned-offset:0px;"><!--[--><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--prev" id="v-0">1 <input type="text"></li><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--active" id="v-1">2 <input type="text"></li><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--next" id="v-2">3 <input type="text"></li><li style="width:50%;" class="carousel__slide" id="v-3">4 <input type="text"></li><li style="width:50%;" class="carousel__slide" id="v-4">5 <input type="text"></li><!--]--></ol></div><!--[--><!--[--><button type="button" aria-label="Navigate to previous slide" title="Navigate to previous slide" class="carousel__prev"><svg class="carousel__icon" viewBox="0 0 24 24" role="img" aria-label="Arrow pointing to the left"><title>Arrow pointing to the left</title><path d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"></path></svg></button><button type="button" aria-label="Navigate to next slide" title="Navigate to next slide" class="carousel__next"><svg class="carousel__icon" viewBox="0 0 24 24" role="img" aria-label="Arrow pointing to the right"><title>Arrow pointing to the right</title><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"></path></svg></button><!--]--><ol class="carousel__pagination"><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 1" aria-pressed="false" aria-controls="v-0" title="Navigate to slide 1"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button carousel__pagination-button--active" aria-label="Navigate to slide 2" aria-pressed="true" aria-controls="v-1" title="Navigate to slide 2"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 3" aria-pressed="false" aria-controls="v-2" title="Navigate to slide 3"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 4" aria-pressed="false" aria-controls="v-3" title="Navigate to slide 4"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 5" aria-pressed="false" aria-controls="v-4" title="Navigate to slide 5"></button></li></ol><!--]--><div class="carousel__liveregion carousel__sr-only" aria-live="polite" aria-atomic="true">Item 2 of 5</div></section></div>"`;
34+
exports[`SSR Carousel > renders server side properly 2`] = `"<div id="app"><section class="carousel is-ltr is-effect-slide" dir="ltr" aria-label="Gallery" tabindex="0"><div class="carousel__viewport"><ol class="carousel__track" style="transform:translateX(0px);--vc-trk-cloned-offset:0px;"><!--[--><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--prev" id="v-0">1 <input type="text"></li><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--active" id="v-1">2 <input type="text"></li><li style="width:50%;" class="carousel__slide carousel__slide--visible carousel__slide--next" id="v-2">3 <input type="text"></li><li style="width:50%;" class="carousel__slide" id="v-3">4 <input type="text"></li><li style="width:50%;" class="carousel__slide" id="v-4">5 <input type="text"></li><!--]--></ol></div><!--[--><!--[--><button type="button" aria-label="Navigate to previous slide" title="Navigate to previous slide" class="carousel__prev"><svg class="carousel__icon" viewBox="0 0 24 24" role="img" aria-label="Arrow pointing to the left"><title>Arrow pointing to the left</title><path d="M15.41 16.59L10.83 12l4.58-4.59L14 6l-6 6 6 6 1.41-1.41z"></path></svg></button><button type="button" aria-label="Navigate to next slide" title="Navigate to next slide" class="carousel__next"><svg class="carousel__icon" viewBox="0 0 24 24" role="img" aria-label="Arrow pointing to the right"><title>Arrow pointing to the right</title><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"></path></svg></button><!--]--><ol class="carousel__pagination"><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 1" aria-pressed="false" aria-controls="v-0" title="Navigate to slide 1"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button carousel__pagination-button--active" aria-label="Navigate to slide 2" aria-pressed="true" aria-controls="v-1" title="Navigate to slide 2"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 3" aria-pressed="false" aria-controls="v-2" title="Navigate to slide 3"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 4" aria-pressed="false" aria-controls="v-3" title="Navigate to slide 4"></button></li><li class="carousel__pagination-item"><button type="button" class="carousel__pagination-button" aria-label="Navigate to slide 5" aria-pressed="false" aria-controls="v-4" title="Navigate to slide 5"></button></li></ol><!--]--><div class="carousel__liveregion carousel__sr-only" aria-live="polite" aria-atomic="true">Item 2 of 5</div></section></div>"`;
3535
3636
exports[`SSR Carousel > renders slotted server side properly 1`] = `
3737
"<div id="app">
38-
<section class="carousel is-ltr" dir="ltr" aria-label="Gallery" tabindex="0">
38+
<section class="carousel is-ltr is-effect-slide" dir="ltr" aria-label="Gallery" tabindex="0">
3939
<div class="carousel__viewport">
4040
<ol class="carousel__track" style="transform: translateX(0px); --vc-trk-cloned-offset: 0px;">
4141
<li style="width: 100%;" class="carousel__slide carousel__slide--clone carousel__slide--prev" aria-hidden="true">5</li>
@@ -51,10 +51,10 @@ exports[`SSR Carousel > renders slotted server side properly 1`] = `
5151
</div>"
5252
`;
5353
54-
exports[`SSR Carousel > renders slotted server side properly 2`] = `"<div id="app"><section class="carousel is-ltr" dir="ltr" aria-label="Gallery" tabindex="0"><div class="carousel__viewport"><ol class="carousel__track" style="transform:translateX(0px);--vc-trk-cloned-offset:0px;"><!--[--><!--[--><li style="width:100%;" class="carousel__slide carousel__slide--visible carousel__slide--active" id="v-0">1</li><li style="width:100%;" class="carousel__slide carousel__slide--next" id="v-1">2</li><li style="width:100%;" class="carousel__slide" id="v-2">3</li><li style="width:100%;" class="carousel__slide" id="v-3">4</li><li style="width:100%;" class="carousel__slide" id="v-4">5</li><!--]--><!--]--></ol></div><!--[--><!--]--><div class="carousel__liveregion carousel__sr-only" aria-live="polite" aria-atomic="true">Item 1 of 5</div></section></div>"`;
54+
exports[`SSR Carousel > renders slotted server side properly 2`] = `"<div id="app"><section class="carousel is-ltr is-effect-slide" dir="ltr" aria-label="Gallery" tabindex="0"><div class="carousel__viewport"><ol class="carousel__track" style="transform:translateX(0px);--vc-trk-cloned-offset:0px;"><!--[--><!--[--><li style="width:100%;" class="carousel__slide carousel__slide--visible carousel__slide--active" id="v-0">1</li><li style="width:100%;" class="carousel__slide carousel__slide--next" id="v-1">2</li><li style="width:100%;" class="carousel__slide" id="v-2">3</li><li style="width:100%;" class="carousel__slide" id="v-3">4</li><li style="width:100%;" class="carousel__slide" id="v-4">5</li><!--]--><!--]--></ol></div><!--[--><!--]--><div class="carousel__liveregion carousel__sr-only" aria-live="polite" aria-atomic="true">Item 1 of 5</div></section></div>"`;
5555
5656
exports[`Wrap around Carousel.ts > renders wrapAround correctly 1`] = `
57-
"<section class="carousel is-ltr" dir="ltr" aria-label="Gallery" tabindex="0">
57+
"<section class="carousel is-ltr is-effect-slide" dir="ltr" aria-label="Gallery" tabindex="0">
5858
<div class="carousel__viewport">
5959
<ol class="carousel__track" style="transform: translateX(0px); --vc-trk-cloned-offset: 0px;">
6060
<li style="width: 33.333333333333336%;" class="carousel__slide" id="v-0">1 <input type="text"></li>

0 commit comments

Comments
 (0)