Browse Source

Refactor carousel (#5292)

* refactor: carousel

* refactor: carousel

* style: update vc-slick path
pull/5317/head
tangjinzhou 3 years ago committed by GitHub
parent
commit
c7492a0b59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      components/carousel/__tests__/__snapshots__/demo.test.js.snap
  2. 24
      components/carousel/__tests__/index.test.js
  3. 1
      components/carousel/demo/customPaging.vue
  4. 8
      components/carousel/index.en-US.md
  5. 270
      components/carousel/index.tsx
  6. 12
      components/carousel/index.zh-CN.md
  7. 94
      components/carousel/style/index.less
  8. 0
      components/carousel/style/index.tsx
  9. 54
      components/carousel/style/rtl.less
  10. 4
      components/vc-slick/arrows.jsx
  11. 2
      components/vc-slick/default-props.js
  12. 39
      components/vc-slick/dots.jsx
  13. 2
      components/vc-slick/index.js
  14. 1
      components/vc-slick/initial-state.js
  15. 79
      components/vc-slick/inner-slider.jsx
  16. 22
      components/vc-slick/slider.jsx
  17. 50
      components/vc-slick/track.jsx
  18. 110
      components/vc-slick/utils/innerSliderUtils.js

12
components/carousel/__tests__/__snapshots__/demo.test.js.snap

@ -2,7 +2,7 @@
exports[`renders ./components/carousel/demo/autoplay.vue correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-slider slick-initialized" dir="ltr">
<!---->
<div class="slick-list">
<div class="slick-track" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">
@ -84,7 +84,7 @@ exports[`renders ./components/carousel/demo/autoplay.vue correctly 1`] = `
exports[`renders ./components/carousel/demo/basic.vue correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-slider slick-initialized" dir="ltr">
<!---->
<div class="slick-list">
<div class="slick-track" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">
@ -166,7 +166,7 @@ exports[`renders ./components/carousel/demo/basic.vue correctly 1`] = `
exports[`renders ./components/carousel/demo/customArrows.vue correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-slider slick-initialized" dir="ltr">
<div class="custom-slick-arrow slick-arrow slick-prev" style="left: 10px; z-index: 1; display: block;"><span role="img" aria-label="left-circle" class="anticon anticon-left-circle"><svg focusable="false" class="" data-icon="left-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M603.3 327.5l-246 178a7.95 7.95 0 000 12.9l246 178c5.3 3.8 12.7 0 12.7-6.5V643c0-10.2-4.9-19.9-13.2-25.9L457.4 512l145.4-105.2c8.3-6 13.2-15.6 13.2-25.9V334c0-6.5-7.4-10.3-12.7-6.5z"></path><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path></svg></span></div>
<div class="slick-list">
<div class="slick-track" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">
@ -248,7 +248,7 @@ exports[`renders ./components/carousel/demo/customArrows.vue correctly 1`] = `
exports[`renders ./components/carousel/demo/customPaging.vue correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized"><button type="button" data-role="none" class="slick-arrow slick-prev" style="display: block;"> Previous</button>
<div class="slick-slider slick-initialized" dir="ltr"><button type="button" data-role="none" class="slick-arrow slick-prev" style="display: block;"> Previous</button>
<div class="slick-list">
<div class="slick-track" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">
<div class="slick-slide slick-cloned" tabindex="-1" data-index="-1" aria-hidden="true" style="width: 0px;">
@ -310,7 +310,7 @@ exports[`renders ./components/carousel/demo/customPaging.vue correctly 1`] = `
exports[`renders ./components/carousel/demo/fade.vue correctly 1`] = `
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-slider slick-initialized" dir="ltr">
<!---->
<div class="slick-list">
<div class="slick-track" style="opacity: 1;">
@ -358,7 +358,7 @@ exports[`renders ./components/carousel/demo/fade.vue correctly 1`] = `
exports[`renders ./components/carousel/demo/position.vue correctly 1`] = `
<div class="ant-radio-group ant-radio-group-outline ant-radio-group-default" style="margin-bottom: 8px;"><label class="ant-radio-button-wrapper ant-radio-button-wrapper-checked"><span class="ant-radio-button ant-radio-button-checked"><input type="radio" class="ant-radio-button-input" value="top"><span class="ant-radio-button-inner"></span></span><span>Top</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="bottom"><span class="ant-radio-button-inner"></span></span><span>Bottom</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="left"><span class="ant-radio-button-inner"></span></span><span>Left</span></label><label class="ant-radio-button-wrapper"><span class="ant-radio-button"><input type="radio" class="ant-radio-button-input" value="right"><span class="ant-radio-button-inner"></span></span><span>Right</span></label></div>
<div class="ant-carousel">
<div class="slick-slider slick-initialized">
<div class="slick-slider slick-initialized" dir="ltr">
<!---->
<div class="slick-list">
<div class="slick-track" style="opacity: 1; transform: translate3d(0px, 0px, 0px);">

24
components/carousel/__tests__/index.test.js

@ -21,9 +21,7 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
const { innerSlider, slick } = wrapper.vm;
const innerSliderFromRefs = slick.innerSlider;
expect(innerSlider).toBe(innerSliderFromRefs);
const { innerSlider } = wrapper.componentVM;
expect(typeof innerSlider.slickNext).toBe('function');
});
@ -39,26 +37,25 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
const { prev, next, goTo } = wrapper.vm;
const { prev, next, goTo, innerSlider } = wrapper.componentVM;
expect(typeof prev).toBe('function');
expect(typeof next).toBe('function');
expect(typeof goTo).toBe('function');
const slick = wrapper.vm.slick;
expect(slick.innerSlider.currentSlide).toBe(0);
expect(innerSlider.currentSlide).toBe(0);
wrapper.vm.goTo(2);
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(2);
expect(innerSlider.currentSlide).toBe(2);
}, 1000);
prev();
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(1);
expect(innerSlider.currentSlide).toBe(1);
}, 1000);
next();
await asyncExpect(() => {
expect(slick.innerSlider.currentSlide).toBe(2);
expect(innerSlider.currentSlide).toBe(2);
}, 1000);
});
// TODO
@ -77,8 +74,8 @@ describe('Carousel', () => {
// sync: false,
// };
// const wrapper = mount(Carousel, props);
// const spy = jest.spyOn(wrapper.vm.slick.innerSlider, 'handleAutoPlay');
// await sleep(100);
// const spy = jest.spyOn(wrapper.componentVM.innerSlider, 'handleAutoPlay');
// window.resizeTo(1000);
// expect(spy).not.toHaveBeenCalled();
// await new Promise(resolve => setTimeout(resolve, 1000));
@ -100,12 +97,9 @@ describe('Carousel', () => {
sync: false,
};
const wrapper = mount(Carousel, props);
const { onWindowResized } = wrapper.vm;
const spy = jest.spyOn(wrapper.vm.onWindowResized, 'cancel');
const spy2 = jest.spyOn(window, 'removeEventListener');
const spy = jest.spyOn(window, 'removeEventListener');
wrapper.unmount();
expect(spy).toHaveBeenCalled();
expect(spy2).toHaveBeenCalledWith('resize', onWindowResized);
});
describe('should works for dotPosition', () => {

1
components/carousel/demo/customPaging.vue

@ -71,6 +71,7 @@ export default defineComponent({
width: 100%;
height: 100%;
filter: grayscale(100%);
display: block;
}
.ant-carousel :deep .slick-thumb li.slick-active img {
filter: grayscale(0%);

8
components/carousel/index.en-US.md

@ -17,14 +17,14 @@ A carousel component. Scales with its container.
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| afterChange | Callback function called after the current index changes | function(current) | - | |
| autoplay | Whether to scroll automatically | boolean | `false` | |
| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
| dots | Whether to show the dots at the bottom of the gallery | boolean | `true` | |
| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | bottom | 1.5.0 |
| dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | `bottom` | 1.5.0 |
| dotsClass | Class name of the dots | string | `slick-dots` | |
| easing | Transition interpolation function name | string | `linear` | |
| effect | Transition effect | `scrollx` \| `fade` | `scrollx` | |
| afterChange | Callback function called after the current index changes | function(current) | - | |
| beforeChange | Callback function called before the current index changes | function(from, to) | - | |
## Methods
@ -34,4 +34,4 @@ A carousel component. Scales with its container.
| next() | Change current slide to next slide | |
| prev() | Change current slide to previous slide | |
For more info on the parameters, refer to the [vc-slick props](https://github.com/vueComponent/ant-design-vue/blob/next/components/vc-slick/src/default-props.js#L3)
For more info on the props, refer to the [carousel props](https://github.com/vueComponent/ant-design-vue/blob/next/components/carousel/index.tsx)

270
components/carousel/index.tsx

@ -1,168 +1,148 @@
import type { ExtractPropTypes } from 'vue';
import { defineComponent, inject } from 'vue';
import type { ExtractPropTypes, PropType } from 'vue';
import { ref, computed, watchEffect, defineComponent } from 'vue';
import PropTypes from '../_util/vue-types';
import debounce from 'lodash-es/debounce';
import hasProp, { getComponent } from '../_util/props-util';
import { defaultConfigProvider } from '../config-provider';
import warning from '../_util/warning';
import classNames from '../_util/classNames';
import SlickCarousel from '../vc-slick/src';
import { tuple, withInstall } from '../_util/type';
import SlickCarousel from '../vc-slick';
import { withInstall } from '../_util/type';
import useConfigInject from '../_util/hooks/useConfigInject';
export type SwipeDirection = 'left' | 'down' | 'right' | 'up' | string;
export type LazyLoadTypes = 'ondemand' | 'progressive';
export type CarouselEffect = 'scrollx' | 'fade';
export type DotPosition = 'top' | 'bottom' | 'left' | 'right';
export interface CarouselRef {
goTo: (slide: number, dontAnimate?: boolean) => void;
next: () => void;
prev: () => void;
autoplay: (palyType?: 'update' | 'leave' | 'blur') => void;
innerSlider: any;
}
// Carousel
export const carouselProps = {
effect: PropTypes.oneOf(tuple('scrollx', 'fade')),
dots: PropTypes.looseBool.def(true),
vertical: PropTypes.looseBool,
autoplay: PropTypes.looseBool,
easing: PropTypes.string,
beforeChange: PropTypes.func,
afterChange: PropTypes.func,
export const carouselProps = () => ({
effect: String as PropType<CarouselEffect>,
dots: { type: Boolean, default: true },
vertical: { type: Boolean, default: undefined },
autoplay: { type: Boolean, default: undefined },
easing: String,
beforeChange: Function as PropType<(currentSlide: number, nextSlide: number) => void>,
afterChange: Function as PropType<(currentSlide: number) => void>,
// style: PropTypes.React.CSSProperties,
prefixCls: PropTypes.string,
accessibility: PropTypes.looseBool,
prefixCls: String,
accessibility: { type: Boolean, default: undefined },
nextArrow: PropTypes.any,
prevArrow: PropTypes.any,
pauseOnHover: PropTypes.looseBool,
// className: PropTypes.string,
adaptiveHeight: PropTypes.looseBool,
arrows: PropTypes.looseBool.def(false),
autoplaySpeed: PropTypes.number,
centerMode: PropTypes.looseBool,
centerPadding: PropTypes.string,
cssEase: PropTypes.string,
dotsClass: PropTypes.string,
draggable: PropTypes.looseBool.def(false),
fade: PropTypes.looseBool,
focusOnSelect: PropTypes.looseBool,
infinite: PropTypes.looseBool,
initialSlide: PropTypes.number,
lazyLoad: PropTypes.looseBool,
rtl: PropTypes.looseBool,
slide: PropTypes.string,
slidesToShow: PropTypes.number,
slidesToScroll: PropTypes.number,
speed: PropTypes.number,
swipe: PropTypes.looseBool,
swipeToSlide: PropTypes.looseBool,
touchMove: PropTypes.looseBool,
touchThreshold: PropTypes.number,
variableWidth: PropTypes.looseBool,
useCSS: PropTypes.looseBool,
slickGoTo: PropTypes.number,
responsive: PropTypes.array,
dotPosition: PropTypes.oneOf(tuple('top', 'bottom', 'left', 'right')),
verticalSwiping: PropTypes.looseBool.def(false),
};
export type CarouselProps = Partial<ExtractPropTypes<typeof carouselProps>>;
pauseOnHover: { type: Boolean, default: undefined },
// className: String,
adaptiveHeight: { type: Boolean, default: undefined },
arrows: { type: Boolean, default: false },
autoplaySpeed: Number,
centerMode: { type: Boolean, default: undefined },
centerPadding: String,
cssEase: String,
dotsClass: String,
draggable: { type: Boolean, default: false },
fade: { type: Boolean, default: undefined },
focusOnSelect: { type: Boolean, default: undefined },
infinite: { type: Boolean, default: undefined },
initialSlide: Number,
lazyLoad: String as PropType<LazyLoadTypes>,
rtl: { type: Boolean, default: undefined },
slide: String,
slidesToShow: Number,
slidesToScroll: Number,
speed: Number,
swipe: { type: Boolean, default: undefined },
swipeToSlide: { type: Boolean, default: undefined },
swipeEvent: Function as PropType<(swipeDirection: SwipeDirection) => void>,
touchMove: { type: Boolean, default: undefined },
touchThreshold: Number,
variableWidth: { type: Boolean, default: undefined },
useCSS: { type: Boolean, default: undefined },
slickGoTo: Number,
responsive: Array,
dotPosition: { type: String as PropType<DotPosition>, default: undefined },
verticalSwiping: { type: Boolean, default: false },
});
export type CarouselProps = Partial<ExtractPropTypes<ReturnType<typeof carouselProps>>>;
const Carousel = defineComponent({
name: 'ACarousel',
inheritAttrs: false,
props: carouselProps,
setup() {
return {
configProvider: inject('configProvider', defaultConfigProvider),
slick: undefined,
innerSlider: undefined,
props: carouselProps(),
setup(props, { slots, attrs, expose }) {
const slickRef = ref();
const goTo = (slide: number, dontAnimate = false) => {
slickRef.value?.slickGoTo(slide, dontAnimate);
};
},
beforeMount() {
this.onWindowResized = debounce(this.onWindowResized, 500, {
leading: false,
});
},
mounted() {
if (hasProp(this, 'vertical')) {
expose({
goTo,
autoplay: palyType => {
slickRef.value?.innerSlider?.handleAutoPlay(palyType);
},
prev: () => {
slickRef.value?.slickPrev();
},
next: () => {
slickRef.value?.slickNext();
},
innerSlider: computed(() => {
return slickRef.value?.innerSlider;
}),
} as CarouselRef);
watchEffect(() => {
warning(
!this.vertical,
props.vertical === undefined,
'Carousel',
'`vertical` is deprecated, please use `dotPosition` instead.',
);
}
const { autoplay } = this;
if (autoplay) {
window.addEventListener('resize', this.onWindowResized);
}
// https://github.com/ant-design/ant-design/issues/7191
this.innerSlider = this.slick && this.slick.innerSlider;
},
beforeUnmount() {
const { autoplay } = this;
if (autoplay) {
window.removeEventListener('resize', this.onWindowResized);
(this.onWindowResized as any).cancel();
}
},
methods: {
getDotPosition() {
if (this.dotPosition) {
return this.dotPosition;
}
if (hasProp(this, 'vertical')) {
return this.vertical ? 'right' : 'bottom';
}
});
const { prefixCls, direction } = useConfigInject('carousel', props);
const dotPosition = computed(() => {
if (props.dotPosition) return props.dotPosition;
if (props.vertical !== undefined) return props.vertical ? 'right' : 'bottom';
return 'bottom';
},
saveSlick(node: HTMLElement) {
this.slick = node;
},
onWindowResized() {
// Fix https://github.com/ant-design/ant-design/issues/2550
const { autoplay } = this;
if (autoplay && this.slick && this.slick.innerSlider && this.slick.innerSlider.autoPlay) {
this.slick.innerSlider.autoPlay();
}
},
next() {
this.slick.slickNext();
},
prev() {
this.slick.slickPrev();
},
goTo(slide: number, dontAnimate = false) {
this.slick.slickGoTo(slide, dontAnimate);
},
},
render() {
const props = { ...this.$props };
const { $slots } = this;
if (props.effect === 'fade') {
props.fade = true;
}
const { class: cls, style, ...restAttrs } = this.$attrs as any;
const getPrefixCls = this.configProvider.getPrefixCls;
let className = getPrefixCls('carousel', props.prefixCls);
const dotsClass = 'slick-dots';
const dotPosition = this.getDotPosition();
props.vertical = dotPosition === 'left' || dotPosition === 'right';
props.dotsClass = classNames(`${dotsClass}`, `${dotsClass}-${dotPosition || 'bottom'}`, {
[`${props.dotsClass}`]: !!props.dotsClass,
});
className = classNames({
[cls]: !!cls,
[className]: !!className,
[`${className}-vertical`]: props.vertical,
const vertical = computed(() => dotPosition.value === 'left' || dotPosition.value === 'right');
const dsClass = computed(() => {
const dotsClass = 'slick-dots';
return classNames({
[dotsClass]: true,
[`${dotsClass}-${dotPosition.value}`]: true,
[`${props.dotsClass}`]: !!props.dotsClass,
});
});
const SlickCarouselProps = {
...props,
...restAttrs,
nextArrow: getComponent(this, 'nextArrow'),
prevArrow: getComponent(this, 'prevArrow'),
return () => {
const { dots, arrows, draggable, effect } = props;
const { class: cls, style, ...restAttrs } = attrs;
const fade = effect === 'fade' ? true : props.fade;
const className = classNames(prefixCls.value, {
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
[`${prefixCls.value}-vertical`]: vertical.value,
[`${cls}`]: !!cls,
});
return (
<div class={className} style={style}>
<SlickCarousel
ref={slickRef}
{...props}
{...restAttrs}
dots={!!dots}
dotsClass={dsClass.value}
arrows={arrows}
draggable={draggable}
fade={fade}
vertical={vertical.value}
v-slots={slots}
/>
</div>
);
};
return (
<div class={className} style={style}>
<SlickCarousel
ref={this.saveSlick}
{...SlickCarouselProps}
v-slots={$slots}
></SlickCarousel>
</div>
);
},
});

12
components/carousel/index.zh-CN.md

@ -18,14 +18,14 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| afterChange | 切换面板的回调 | function(current) | 无 | |
| autoplay | 是否自动切换 | boolean | false | |
| beforeChange | 切换面板的回调 | function(from, to) | 无 | |
| dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | bottom | 1.5.0 |
| dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | `bottom` | 1.5.0 |
| dots | 是否显示面板指示点 | boolean | true | |
| dotsClass | 面板指示点类名 | string | `slick-dots` | |
| easing | 动画效果 | string | linear | |
| effect | 动画效果函数,可取 scrollx, fade | string | scrollx | |
| easing | 动画效果 | string | `linear` | |
| effect | 动画效果函数 | `scrollx` \| `fade` | `scrollx` | |
| afterChange | 切换面板的回调 | function(current) | - | |
| beforeChange | 切换面板的回调 | function(from, to) | - | |
## 方法
@ -35,4 +35,4 @@ cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
| next() | 切换到下一面板 | |
| prev() | 切换到上一面板 | |
更多参数可参考:[vc-slick props](https://github.com/vueComponent/ant-design-vue/blob/next/components/vc-slick/src/default-props.js#L3)
更多属性可参考源码:[carousel props](https://github.com/vueComponent/ant-design-vue/blob/next/components/carousel/index.tsx)

94
components/carousel/style/index.less

@ -1,18 +1,20 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
.@{ant-prefix}-carousel {
@carousel-prefix-cls: ~'@{ant-prefix}-carousel';
.@{carousel-prefix-cls} {
.reset-component();
.slick-slider {
position: relative;
display: block;
box-sizing: border-box;
-webkit-touch-callout: none;
-ms-touch-action: pan-y;
touch-action: pan-y;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
.slick-list {
position: relative;
display: block;
@ -45,11 +47,20 @@
visibility: visible;
}
}
// fix Carousel content height not match parent node
// when children is empty node
// https://github.com/ant-design/ant-design/issues/25878
> div > div {
vertical-align: bottom;
}
}
}
.slick-slider .slick-track,
.slick-slider .slick-list {
transform: translate3d(0, 0, 0);
touch-action: pan-y;
}
.slick-track {
@ -72,17 +83,17 @@
visibility: hidden;
}
}
.slick-slide {
display: none;
float: left;
height: 100%;
min-height: 1px;
[dir='rtl'] & {
float: right;
}
img {
display: block;
}
&.slick-loading img {
display: none;
}
@ -103,8 +114,8 @@
.slick-vertical .slick-slide {
display: block;
height: auto;
border: @border-width-base @border-style-base transparent;
}
.slick-arrow.slick-hidden {
display: none;
}
@ -126,15 +137,18 @@
border: 0;
outline: none;
cursor: pointer;
&:hover,
&:focus {
color: transparent;
background: transparent;
outline: none;
&::before {
opacity: 1;
}
}
&.slick-disabled::before {
opacity: 0.25;
}
@ -142,6 +156,7 @@
.slick-prev {
left: -25px;
&::before {
content: '←';
}
@ -149,6 +164,7 @@
.slick-next {
right: -25px;
&::before {
content: '→';
}
@ -157,29 +173,45 @@
// Dots
.slick-dots {
position: absolute;
display: block;
width: 100%;
height: @carousel-dot-height;
margin: 0;
padding: 0;
text-align: center;
right: 0;
bottom: 0;
left: 0;
z-index: 15;
display: flex !important;
justify-content: center;
margin-right: 15%;
margin-left: 15%;
padding-left: 0;
list-style: none;
&-bottom {
bottom: 12px;
}
&-top {
top: 12px;
bottom: auto;
}
li {
position: relative;
display: inline-block;
flex: 0 1 auto;
box-sizing: content-box;
width: @carousel-dot-width;
height: @carousel-dot-height;
margin: 0 2px;
margin-right: 3px;
margin-left: 3px;
padding: 0;
text-align: center;
text-indent: -999px;
vertical-align: top;
transition: all 0.5s;
button {
display: block;
width: @carousel-dot-width;
width: 100%;
height: @carousel-dot-height;
padding: 0;
color: transparent;
@ -191,15 +223,21 @@
cursor: pointer;
opacity: 0.3;
transition: all 0.5s;
&:hover,
&:focus {
opacity: 0.75;
}
}
&.slick-active button {
&.slick-active {
width: @carousel-dot-active-width;
background: @component-background;
opacity: 1;
& button {
background: @component-background;
opacity: 1;
}
&:hover,
&:focus {
opacity: 1;
@ -213,26 +251,44 @@
.slick-dots {
top: 50%;
bottom: auto;
flex-direction: column;
width: @carousel-dot-height;
height: auto;
margin: 0;
transform: translateY(-50%);
&-left {
right: auto;
left: 12px;
}
&-right {
right: 12px;
left: auto;
}
li {
margin: 0 2px;
width: @carousel-dot-height;
height: @carousel-dot-width;
margin: 4px 2px;
vertical-align: baseline;
button {
width: @carousel-dot-height;
height: @carousel-dot-width;
}
&.slick-active button {
&.slick-active {
width: @carousel-dot-height;
height: @carousel-dot-active-width;
button {
width: @carousel-dot-height;
height: @carousel-dot-active-width;
}
}
}
}
}
@import './rtl';

0
components/carousel/style/index.ts → components/carousel/style/index.tsx

54
components/carousel/style/rtl.less

@ -0,0 +1,54 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@carousel-prefix-cls: ~'@{ant-prefix}-carousel';
.@{carousel-prefix-cls} {
&-rtl {
direction: rtl;
}
.slick-track {
.@{carousel-prefix-cls}-rtl & {
right: 0;
left: auto;
}
}
.slick-prev {
.@{carousel-prefix-cls}-rtl & {
right: -25px;
left: auto;
&::before {
content: '→';
}
}
}
.slick-next {
.@{carousel-prefix-cls}-rtl & {
right: auto;
left: -25px;
&::before {
content: '←';
}
}
}
// Dots
.slick-dots {
.@{carousel-prefix-cls}-rtl& {
flex-direction: row-reverse;
}
}
}
.@{ant-prefix}-carousel-vertical {
.slick-dots {
.@{carousel-prefix-cls}-rtl& {
flex-direction: column;
}
}
}

4
components/vc-slick/src/arrows.jsx → components/vc-slick/arrows.jsx

@ -1,5 +1,5 @@
import classnames from '../../_util/classNames';
import { cloneElement } from '../../_util/vnode';
import classnames from '../_util/classNames';
import { cloneElement } from '../_util/vnode';
import { canGoNext } from './utils/innerSliderUtils';
function noop() {}

2
components/vc-slick/src/default-props.js → components/vc-slick/default-props.js

@ -1,4 +1,4 @@
import PropTypes from '../../_util/vue-types';
import PropTypes from '../_util/vue-types';
const defaultProps = {
accessibility: PropTypes.looseBool.def(true),

39
components/vc-slick/src/dots.jsx → components/vc-slick/dots.jsx

@ -1,5 +1,6 @@
import classnames from '../../_util/classNames';
import { cloneElement } from '../../_util/vnode';
import classnames from '../_util/classNames';
import { cloneElement } from '../_util/vnode';
import { clamp } from './utils/innerSliderUtils';
const getDotCount = function (spec) {
let dots;
@ -39,24 +40,26 @@ const Dots = (_, { attrs }) => {
//
// Credit: http://stackoverflow.com/a/13735425/1849458
const mouseEvents = { onMouseenter, onMouseover, onMouseleave };
const dots = Array.apply(
null,
Array(dotCount + 1)
.join('0')
.split(''),
).map((x, i) => {
const leftBound = i * slidesToScroll;
const rightBound = i * slidesToScroll + (slidesToScroll - 1);
const className = classnames({
'slick-active': currentSlide >= leftBound && currentSlide <= rightBound,
let dots = [];
for (let i = 0; i < dotCount; i++) {
let _rightBound = (i + 1) * slidesToScroll - 1;
let rightBound = infinite ? _rightBound : clamp(_rightBound, 0, slideCount - 1);
let _leftBound = rightBound - (slidesToScroll - 1);
let leftBound = infinite ? _leftBound : clamp(_leftBound, 0, slideCount - 1);
let className = classnames({
'slick-active': infinite
? currentSlide >= leftBound && currentSlide <= rightBound
: currentSlide === leftBound,
});
const dotOptions = {
let dotOptions = {
message: 'dots',
index: i,
slidesToScroll,
currentSlide,
};
function onClick(e) {
// In Autoplay the focus stays on clicked button even after transition
// to next slide. That only goes away by click somewhere outside
@ -65,14 +68,12 @@ const Dots = (_, { attrs }) => {
}
clickHandler(dotOptions);
}
return (
dots = dots.concat(
<li key={i} class={className}>
{cloneElement(customPaging({ i }), {
onClick,
})}
</li>
{cloneElement(customPaging({ i }), { onClick })}
</li>,
);
});
}
return cloneElement(appendDots({ dots }), {
class: dotsClass,

2
components/vc-slick/src/index.js → components/vc-slick/index.js

@ -1,4 +1,4 @@
// base react-slick 0.23.2
// base react-slick 0.28.2
import Slider from './slider';
export default Slider;

1
components/vc-slick/src/initial-state.js → components/vc-slick/initial-state.js

@ -21,6 +21,7 @@ const initialState = {
touchObject: { startX: 0, startY: 0, curX: 0, curY: 0 },
trackStyle: {},
trackWidth: 0,
targetSlide: 0,
};
export default initialState;

79
components/vc-slick/src/inner-slider.jsx → components/vc-slick/inner-slider.jsx

@ -1,7 +1,7 @@
import debounce from 'lodash-es/debounce';
import ResizeObserver from 'resize-observer-polyfill';
import classnames from '../../_util/classNames';
import BaseMixin from '../../_util/BaseMixin';
import classnames from '../_util/classNames';
import BaseMixin from '../_util/BaseMixin';
import defaultProps from './default-props';
import initialState from './initial-state';
import {
@ -24,7 +24,7 @@ import {
import Track from './track';
import Dots from './dots';
import { PrevArrow, NextArrow } from './arrows';
import supportsPassive from '../../_util/supportsPassive';
import supportsPassive from '../_util/supportsPassive';
function noop() {}
@ -42,10 +42,12 @@ export default {
this.callbackTimers = [];
this.clickable = true;
this.debouncedResize = null;
const ssrState = this.ssrInit();
return {
...initialState,
currentSlide: this.initialSlide,
slideCount: this.children.length,
...ssrState,
};
},
watch: {
@ -83,7 +85,9 @@ export default {
currentSlide: this.currentSlide,
});
}
if (nextProps.autoplay) {
if (!this.preProps.autoplay && nextProps.autoplay) {
this.handleAutoPlay('playing');
} else if (nextProps.autoplay) {
this.handleAutoPlay('update');
} else {
this.pause('paused');
@ -92,8 +96,7 @@ export default {
this.preProps = { ...nextProps };
},
},
beforeMount() {
this.ssrInit();
mounted() {
this.__emit('init');
if (this.lazyLoad) {
const slidesToLoad = getOnDemandLazySlides({
@ -107,8 +110,6 @@ export default {
this.__emit('lazyLoad', slidesToLoad);
}
}
},
mounted() {
this.$nextTick(() => {
const spec = {
listRef: this.list,
@ -118,7 +119,7 @@ export default {
};
this.updateState(spec, true, () => {
this.adaptHeight();
this.autoplay && this.handleAutoPlay('update');
this.autoplay && this.handleAutoPlay('playing');
});
if (this.lazyLoad === 'progressive') {
this.lazyLoadTimer = setInterval(this.progressiveLazyLoad, 1000);
@ -132,14 +133,11 @@ export default {
}
});
this.ro.observe(this.list);
Array.prototype.forEach.call(document.querySelectorAll('.slick-slide'), slide => {
slide.onfocus = this.$props.pauseOnFocus ? this.onSlideFocus : null;
slide.onblur = this.$props.pauseOnFocus ? this.onSlideBlur : null;
});
// To support server-side rendering
if (!window) {
return;
}
document.querySelectorAll &&
Array.prototype.forEach.call(document.querySelectorAll('.slick-slide'), slide => {
slide.onfocus = this.$props.pauseOnFocus ? this.onSlideFocus : null;
slide.onblur = this.$props.pauseOnFocus ? this.onSlideBlur : null;
});
if (window.addEventListener) {
window.addEventListener('resize', this.onWindowResized);
} else {
@ -166,6 +164,7 @@ export default {
if (this.autoplayTimer) {
clearInterval(this.autoplayTimer);
}
this.ro?.disconnect();
},
updated() {
this.checkImagesLoad();
@ -206,7 +205,8 @@ export default {
this.debouncedResize();
},
resizeWindow(setTrackStyle = true) {
if (!this.track) return;
const isTrackMounted = Boolean(this.track);
if (!isTrackMounted) return;
const spec = {
listRef: this.list,
trackRef: this.track,
@ -278,10 +278,9 @@ export default {
const currentWidth = `${childrenWidths[this.currentSlide]}px`;
trackStyle.left = `calc(${trackStyle.left} + (100% - ${currentWidth}) / 2 ) `;
}
this.setState({
return {
trackStyle,
});
return;
};
}
const childrenCount = children.length;
const spec = { ...this.$props, ...this.$data, slideCount: childrenCount };
@ -296,13 +295,17 @@ export default {
width: trackWidth + '%',
left: trackLeft + '%',
};
this.setState({
return {
slideWidth: slideWidth + '%',
trackStyle,
});
};
},
checkImagesLoad() {
const images = document.querySelectorAll('.slick-slide img');
let images =
(this.list &&
this.list.querySelectorAll &&
this.list.querySelectorAll('.slick-slide img')) ||
[];
const imagesCount = images.length;
let loadedCount = 0;
Array.prototype.forEach.call(images, image => {
@ -376,10 +379,16 @@ export default {
if (this.$attrs.onLazyLoad && slidesToLoad.length > 0) {
this.__emit('lazyLoad', slidesToLoad);
}
if (!this.$props.waitForAnimate && this.animationEndCallback) {
clearTimeout(this.animationEndCallback);
afterChange && afterChange(currentSlide);
delete this.animationEndCallback;
}
this.setState(state, () => {
asNavFor &&
asNavFor.innerSlider.currentSlide !== currentSlide &&
if (asNavFor && this.asNavForIndex !== index) {
this.asNavForIndex = index;
asNavFor.innerSlider.slideHandler(index);
}
if (!nextState) return;
this.animationEndCallback = setTimeout(() => {
const { animating, ...firstBatch } = nextState;
@ -400,6 +409,11 @@ export default {
} else {
this.slideHandler(targetSlide);
}
this.$props.autoplay && this.handleAutoPlay('update');
if (this.$props.focusOnSelect) {
const nodes = this.list.querySelectorAll('.slick-current');
nodes[0] && nodes[0].focus();
}
},
clickHandler(e) {
if (this.clickable === false) {
@ -465,6 +479,10 @@ export default {
this.enableBodyScroll();
}
},
touchEnd(e) {
this.swipeEnd(e);
this.clickable = true;
},
slickPrev() {
// this and fellow methods are wrapped in setTimeout
// to make sure initialize setState has happened before
@ -599,11 +617,13 @@ export default {
'variableWidth',
'unslick',
'centerPadding',
'targetSlide',
'useCSS',
]);
const { pauseOnHover } = this.$props;
trackProps = {
...trackProps,
focusOnSelect: this.focusOnSelect ? this.selectHandler : null,
focusOnSelect: this.focusOnSelect && this.clickable ? this.selectHandler : null,
ref: this.trackRefHandler,
onMouseleave: pauseOnHover ? this.onTrackLeave : noop,
onMouseover: pauseOnHover ? this.onTrackOver : noop,
@ -701,14 +721,15 @@ export default {
: noop,
[supportsPassive ? 'onTouchmovePassive' : 'onTouchmove']:
this.dragging && touchMove ? this.swipeMove : noop,
onTouchend: touchMove ? this.swipeEnd : noop,
onTouchend: touchMove ? this.touchEnd : noop,
onTouchcancel: this.dragging && touchMove ? this.swipeEnd : noop,
onKeydown: this.accessibility ? this.keyHandler : noop,
};
let innerSliderProps = {
class: className,
// dir: 'ltr',
dir: 'ltr',
style: this.$attrs.style,
};
if (this.unslick) {

22
components/vc-slick/src/slider.jsx → components/vc-slick/slider.jsx

@ -1,10 +1,10 @@
import json2mq from '../../_util/json2mq';
import BaseMixin from '../../_util/BaseMixin';
import { cloneElement } from '../../_util/vnode';
import json2mq from '../_util/json2mq';
import BaseMixin from '../_util/BaseMixin';
import { cloneElement } from '../_util/vnode';
import InnerSlider from './inner-slider';
import defaultProps from './default-props';
import { canUseDOM } from './utils/innerSliderUtils';
import { getSlot } from '../../_util/props-util';
import { getSlot } from '../_util/props-util';
import { defineComponent } from 'vue';
export default defineComponent({
@ -21,7 +21,7 @@ export default defineComponent({
};
},
// handles responsive breakpoints
beforeMount() {
mounted() {
if (this.responsive) {
const breakpoints = this.responsive.map(breakpt => breakpt.breakpoint);
// sort them in increasing order of their numerical value
@ -77,19 +77,19 @@ export default defineComponent({
this._responsiveMediaHandlers.push({ mql, query, listener });
},
slickPrev() {
this.innerSlider.slickPrev();
this.innerSlider?.slickPrev();
},
slickNext() {
this.innerSlider.slickNext();
this.innerSlider?.slickNext();
},
slickGoTo(slide, dontAnimate = false) {
this.innerSlider.slickGoTo(slide, dontAnimate);
this.innerSlider?.slickGoTo(slide, dontAnimate);
},
slickPause() {
this.innerSlider.pause('paused');
this.innerSlider?.pause('paused');
},
slickPlay() {
this.innerSlider.handleAutoPlay('play');
this.innerSlider?.handleAutoPlay('play');
},
},
@ -185,7 +185,7 @@ export default defineComponent({
if (settings === 'unslick') {
const className = 'regular slider ' + (this.className || '');
return <div class={className}>{newChildren}</div>;
return <div class={className}>{children}</div>;
} else if (newChildren.length <= settings.slidesToShow) {
settings.unslick = true;
}

50
components/vc-slick/src/track.jsx → components/vc-slick/track.jsx

@ -1,7 +1,7 @@
import { createVNode } from 'vue';
import classnames from '../../_util/classNames';
import { cloneElement } from '../../_util/vnode';
import { flattenChildren } from '../../_util/props-util';
import classnames from '../_util/classNames';
import { cloneElement } from '../_util/vnode';
import { flattenChildren } from '../_util/props-util';
import { lazyStartIndex, lazyEndIndex, getPreClones } from './utils/innerSliderUtils';
// given specifications/props for a slide, fetch all the classes that need to be applied to the slide
@ -24,7 +24,15 @@ const getSlideClasses = spec => {
} else {
slickActive = spec.currentSlide <= index && index < spec.currentSlide + spec.slidesToShow;
}
const slickCurrent = index === spec.currentSlide;
let focusedSlide;
if (spec.targetSlide < 0) {
focusedSlide = spec.targetSlide + spec.slideCount;
} else if (spec.targetSlide >= spec.slideCount) {
focusedSlide = spec.targetSlide - spec.slideCount;
} else {
focusedSlide = spec.targetSlide;
}
let slickCurrent = index === focusedSlide;
return {
'slick-slide': true,
'slick-active': slickActive,
@ -49,32 +57,24 @@ const getSlideStyle = function (spec) {
style.left = -spec.index * parseInt(spec.slideWidth) + 'px';
}
style.opacity = spec.currentSlide === spec.index ? 1 : 0;
style.transition =
'opacity ' +
spec.speed +
'ms ' +
spec.cssEase +
', ' +
'visibility ' +
spec.speed +
'ms ' +
spec.cssEase;
style.WebkitTransition =
'opacity ' +
spec.speed +
'ms ' +
spec.cssEase +
', ' +
'visibility ' +
spec.speed +
'ms ' +
spec.cssEase;
if (spec.useCSS) {
style.transition =
'opacity ' +
spec.speed +
'ms ' +
spec.cssEase +
', ' +
'visibility ' +
spec.speed +
'ms ' +
spec.cssEase;
}
}
return style;
};
const getKey = (child, fallbackKey) => child.key || (child.key === 0 && '0') || fallbackKey;
const getKey = (child, fallbackKey) => child.key + '-' + fallbackKey;
const renderSlides = function (spec, children) {
let key;

110
components/vc-slick/src/utils/innerSliderUtils.js → components/vc-slick/utils/innerSliderUtils.js

@ -1,4 +1,15 @@
import supportsPassive from '../../../_util/supportsPassive';
// import supportsPassive from '../../../_util/supportsPassive';
export function clamp(number, lowerBound, upperBound) {
return Math.max(lowerBound, Math.min(number, upperBound));
}
export const safePreventDefault = event => {
const passiveEvents = ['touchstart', 'touchmove', 'wheel'];
if (!passiveEvents.includes(event.type)) {
event.preventDefault();
}
};
export const getOnDemandLazySlides = spec => {
const onDemandSlides = [];
@ -91,8 +102,10 @@ export const extractObject = (spec, keys) => {
export const initializedState = spec => {
// spec also contains listRef, trackRef
const slideCount = spec.children.length;
const listWidth = Math.ceil(getWidth(spec.listRef));
const trackWidth = Math.ceil(getWidth(spec.trackRef));
const listNode = spec.listRef;
const listWidth = Math.ceil(getWidth(listNode));
const trackNode = spec.trackRef;
const trackWidth = Math.ceil(getWidth(trackNode));
let slideWidth;
if (!spec.vertical) {
let centerPaddingAdj = spec.centerMode && parseInt(spec.centerPadding) * 2;
@ -103,15 +116,15 @@ export const initializedState = spec => {
} else {
slideWidth = listWidth;
}
const slideHeight = spec.listRef && getHeight(spec.listRef.querySelector('[data-index="0"]'));
const slideHeight = listNode && getHeight(listNode.querySelector('[data-index="0"]'));
const listHeight = slideHeight * spec.slidesToShow;
let currentSlide = spec.currentSlide === undefined ? spec.initialSlide : spec.currentSlide;
if (spec.rtl && spec.currentSlide === undefined) {
currentSlide = slideCount - 1 - spec.initialSlide;
}
const lazyLoadedList = spec.lazyLoadedList || [];
const slidesToLoad = getOnDemandLazySlides({ currentSlide, lazyLoadedList }, spec);
lazyLoadedList.concat(slidesToLoad);
let lazyLoadedList = spec.lazyLoadedList || [];
const slidesToLoad = getOnDemandLazySlides({ ...spec, currentSlide, lazyLoadedList }, spec);
lazyLoadedList = lazyLoadedList.concat(slidesToLoad);
const state = {
slideCount,
@ -139,7 +152,6 @@ export const slideHandler = spec => {
infinite,
index,
slideCount,
lazyLoadedList,
lazyLoad,
currentSlide,
centerMode,
@ -147,6 +159,7 @@ export const slideHandler = spec => {
slidesToShow,
useCSS,
} = spec;
let { lazyLoadedList } = spec;
if (waitForAnimate && animating) return {};
let animationSlide = index;
let finalSlide;
@ -154,6 +167,7 @@ export const slideHandler = spec => {
let finalLeft;
let state = {};
let nextState = {};
const targetSlide = infinite ? index : clamp(index, 0, slideCount - 1);
if (fade) {
if (!infinite && (index < 0 || index >= slideCount)) return {};
if (index < 0) {
@ -162,14 +176,15 @@ export const slideHandler = spec => {
animationSlide = index - slideCount;
}
if (lazyLoad && lazyLoadedList.indexOf(animationSlide) < 0) {
lazyLoadedList.push(animationSlide);
lazyLoadedList = lazyLoadedList.concat(animationSlide);
}
state = {
animating: true,
currentSlide: animationSlide,
lazyLoadedList,
targetSlide: animationSlide,
};
nextState = { animating: false };
nextState = { animating: false, targetSlide: animationSlide };
} else {
finalSlide = animationSlide;
if (animationSlide < 0) {
@ -188,19 +203,28 @@ export const slideHandler = spec => {
if (!infinite) finalSlide = slideCount - slidesToShow;
else if (slideCount % slidesToScroll !== 0) finalSlide = 0;
}
if (!infinite && animationSlide + slidesToShow >= slideCount) {
finalSlide = slideCount - slidesToShow;
}
animationLeft = getTrackLeft({ ...spec, slideIndex: animationSlide });
finalLeft = getTrackLeft({ ...spec, slideIndex: finalSlide });
if (!infinite) {
if (animationLeft === finalLeft) animationSlide = finalSlide;
animationLeft = finalLeft;
}
lazyLoad &&
lazyLoadedList.concat(getOnDemandLazySlides({ ...spec, currentSlide: animationSlide }));
if (lazyLoad) {
lazyLoadedList = lazyLoadedList.concat(
getOnDemandLazySlides({ ...spec, currentSlide: animationSlide }),
);
}
if (!useCSS) {
state = {
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
lazyLoadedList,
targetSlide,
};
} else {
state = {
@ -208,12 +232,14 @@ export const slideHandler = spec => {
currentSlide: finalSlide,
trackStyle: getTrackAnimateCSS({ ...spec, left: animationLeft }),
lazyLoadedList,
targetSlide,
};
nextState = {
animating: false,
currentSlide: finalSlide,
trackStyle: getTrackCSS({ ...spec, left: finalLeft }),
swipeLeft: null,
targetSlide,
};
}
}
@ -222,7 +248,15 @@ export const slideHandler = spec => {
export const changeSlide = (spec, options) => {
let previousInt, slideOffset, targetSlide;
const { slidesToScroll, slidesToShow, slideCount, currentSlide, lazyLoad, infinite } = spec;
const {
slidesToScroll,
slidesToShow,
slideCount,
currentSlide,
targetSlide: previousTargetSlide,
lazyLoad,
infinite,
} = spec;
const unevenOffset = slideCount % slidesToScroll !== 0;
const indexOffset = unevenOffset ? 0 : (slideCount - currentSlide) % slidesToScroll;
@ -233,24 +267,25 @@ export const changeSlide = (spec, options) => {
previousInt = currentSlide - slideOffset;
targetSlide = previousInt === -1 ? slideCount - 1 : previousInt;
}
if (!infinite) {
targetSlide = previousTargetSlide - slidesToScroll;
}
} else if (options.message === 'next') {
slideOffset = indexOffset === 0 ? slidesToScroll : indexOffset;
targetSlide = currentSlide + slideOffset;
if (lazyLoad && !infinite) {
targetSlide = ((currentSlide + slidesToScroll) % slideCount) + indexOffset;
}
if (!infinite) {
targetSlide = previousTargetSlide + slidesToScroll;
}
} else if (options.message === 'dots') {
// Click on dots
targetSlide = options.index * options.slidesToScroll;
if (targetSlide === options.currentSlide) {
return null;
}
} else if (options.message === 'children') {
// Click on the slides
targetSlide = options.index;
if (targetSlide === options.currentSlide) {
return null;
}
if (infinite) {
const direction = siblingDirection({ ...spec, targetSlide });
if (targetSlide > options.currentSlide && direction === 'left') {
@ -261,9 +296,6 @@ export const changeSlide = (spec, options) => {
}
} else if (options.message === 'index') {
targetSlide = Number(options.index);
if (targetSlide === options.currentSlide) {
return null;
}
}
return targetSlide;
};
@ -277,7 +309,7 @@ export const keyHandler = (e, accessibility, rtl) => {
};
export const swipeStart = (e, swipe, draggable) => {
e.target.tagName === 'IMG' && !supportsPassive && e.preventDefault();
e.target.tagName === 'IMG' && safePreventDefault.preventDefault();
if (!swipe || (!draggable && e.type.indexOf('mouse') !== -1)) return '';
return {
dragging: true,
@ -313,11 +345,8 @@ export const swipeMove = (e, spec) => {
listWidth,
} = spec;
if (scrolling) return;
if (animating) {
!supportsPassive && e.preventDefault();
return;
}
if (vertical && swipeToSlide && verticalSwiping) !supportsPassive && e.preventDefault();
if (animating) return safePreventDefault(e);
if (vertical && swipeToSlide && verticalSwiping) safePreventDefault(e);
let swipeLeft;
let state = {};
const curLeft = getTrackLeft(spec);
@ -343,9 +372,9 @@ export const swipeMove = (e, spec) => {
let touchSwipeLength = touchObject.swipeLength;
if (!infinite) {
if (
(currentSlide === 0 && swipeDirection === 'right') ||
(currentSlide + 1 >= dotCount && swipeDirection === 'left') ||
(!canGoNext(spec) && swipeDirection === 'left')
(currentSlide === 0 && (swipeDirection === 'right' || swipeDirection === 'down')) ||
(currentSlide + 1 >= dotCount && (swipeDirection === 'left' || swipeDirection === 'up')) ||
(!canGoNext(spec) && (swipeDirection === 'left' || swipeDirection === 'up'))
) {
touchSwipeLength = touchObject.swipeLength * edgeFriction;
if (edgeDragged === false && onEdge) {
@ -384,7 +413,7 @@ export const swipeMove = (e, spec) => {
}
if (touchObject.swipeLength > 10) {
state['swiping'] = true;
!supportsPassive && e.preventDefault();
safePreventDefault(e);
}
return state;
};
@ -397,13 +426,15 @@ export const swipeEnd = (e, spec) => {
touchThreshold,
verticalSwiping,
listHeight,
currentSlide,
swipeToSlide,
scrolling,
onSwipe,
targetSlide,
currentSlide,
infinite,
} = spec;
if (!dragging) {
if (swipe) e.preventDefault();
if (swipe) safePreventDefault(e);
return {};
}
const minSwipe = verticalSwiping ? listHeight / touchThreshold : listWidth / touchThreshold;
@ -425,26 +456,27 @@ export const swipeEnd = (e, spec) => {
return state;
}
if (touchObject.swipeLength > minSwipe) {
e.preventDefault();
safePreventDefault(e);
if (onSwipe) {
onSwipe(swipeDirection);
}
let slideCount, newSlide;
let activeSlide = infinite ? currentSlide : targetSlide;
switch (swipeDirection) {
case 'left':
case 'up':
newSlide = currentSlide + getSlideCount(spec);
newSlide = activeSlide + getSlideCount(spec);
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide;
state['currentDirection'] = 0;
break;
case 'right':
case 'down':
newSlide = currentSlide - getSlideCount(spec);
newSlide = activeSlide - getSlideCount(spec);
slideCount = swipeToSlide ? checkNavigable(spec, newSlide) : newSlide;
state['currentDirection'] = 1;
break;
default:
slideCount = currentSlide;
slideCount = activeSlide;
}
state['triggerSlideHandler'] = slideCount;
} else {
@ -487,7 +519,7 @@ export const getSlideCount = spec => {
if (spec.swipeToSlide) {
let swipedSlide;
const slickList = spec.listRef;
const slides = slickList.querySelectorAll('.slick-slide');
const slides = (slickList.querySelectorAll && slickList.querySelectorAll('.slick-slide')) || [];
Array.from(slides).every(slide => {
if (!spec.vertical) {
if (slide.offsetLeft - centerOffset + getWidth(slide) / 2 > spec.swipeLeft * -1) {
Loading…
Cancel
Save