refactor:carousel (#6262)

* refactor:carousel

* docs:update & refactor: carousel type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
pull/6263/head^2
果冻橙 2023-02-13 17:46:06 +08:00 committed by GitHub
parent e9ce4eb2d5
commit bbfb3cef7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 422 additions and 410 deletions

View File

@ -26,15 +26,14 @@ Timing of scrolling to the next card/picture.
</template>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
:deep(.slick-slide) {
text-align: center;
height: 160px;
line-height: 160px;
background: #364d79;
overflow: hidden;
}
.ant-carousel :deep(.slick-slide h3) {
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -41,7 +41,7 @@ export default defineComponent({
</script>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
:deep(.slick-slide) {
text-align: center;
height: 160px;
line-height: 160px;
@ -49,7 +49,7 @@ export default defineComponent({
overflow: hidden;
}
.ant-carousel :deep(.slick-slide h3) {
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -46,7 +46,7 @@ export default defineComponent({
</script>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
:deep(.slick-slide) {
text-align: center;
height: 160px;
line-height: 160px;
@ -54,23 +54,25 @@ export default defineComponent({
overflow: hidden;
}
.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
:deep(.slick-arrow.custom-slick-arrow) {
width: 25px;
height: 25px;
font-size: 25px;
color: #fff;
background-color: rgba(31, 45, 61, 0.11);
transition: ease all 0.3s;
opacity: 0.3;
z-index: 1;
}
.ant-carousel :deep(.custom-slick-arrow:before) {
:deep(.slick-arrow.custom-slick-arrow:before) {
display: none;
}
.ant-carousel :deep(.custom-slick-arrow:hover) {
:deep(.slick-arrow.custom-slick-arrow:hover) {
color: #fff;
opacity: 0.5;
}
.ant-carousel :deep(.slick-slide h3) {
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -46,33 +46,33 @@ export default defineComponent({
</script>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-dots) {
:deep(.slick-dots) {
position: relative;
height: auto;
}
.ant-carousel :deep(.slick-slide img) {
:deep(.slick-slide img) {
border: 5px solid #fff;
display: block;
margin: auto;
max-width: 80%;
}
.ant-carousel :deep(.slick-arrow) {
:deep(.slick-arrow) {
display: none !important;
}
.ant-carousel :deep(.slick-thumb) {
:deep(.slick-thumb) {
bottom: 0px;
}
.ant-carousel :deep(.slick-thumb li) {
:deep(.slick-thumb li) {
width: 60px;
height: 45px;
}
.ant-carousel :deep(.slick-thumb li img) {
:deep(.slick-thumb li img) {
width: 100%;
height: 100%;
filter: grayscale(100%);
display: block;
}
.ant-carousel :deep .slick-thumb li.slick-active img {
:deep .slick-thumb li.slick-active img {
filter: grayscale(0%);
}
</style>

View File

@ -26,7 +26,7 @@ Slides use fade for transition.
</template>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
:deep(.slick-slide) {
text-align: center;
height: 160px;
line-height: 160px;
@ -34,7 +34,7 @@ Slides use fade for transition.
overflow: hidden;
}
.ant-carousel :deep(.slick-slide h3) {
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -43,7 +43,7 @@ export default defineComponent({
</script>
<style scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
:deep(.slick-slide) {
text-align: center;
height: 160px;
line-height: 160px;
@ -51,7 +51,7 @@ export default defineComponent({
overflow: hidden;
}
.ant-carousel :deep(.slick-slide h3) {
:deep(.slick-slide h3) {
color: #fff;
}
</style>

View File

@ -2,7 +2,7 @@
category: Components
type: Data Display
title: Carousel
cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*bPMSSqbaTMkAAAAAAAAAAAAADrJ8AQ/original
---
A carousel component. Scales with its container.

View File

@ -1,12 +1,15 @@
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
import type { CSSProperties, ExtractPropTypes } from 'vue';
import { ref, computed, watchEffect, defineComponent } from 'vue';
import PropTypes from '../_util/vue-types';
import warning from '../_util/warning';
import classNames from '../_util/classNames';
import SlickCarousel from '../vc-slick';
import { withInstall } from '../_util/type';
import { withInstall, booleanType, functionType, stringType } from '../_util/type';
import useConfigInject from '../config-provider/hooks/useConfigInject';
// CSSINJS
import useStyle from './style';
export type SwipeDirection = 'left' | 'down' | 'right' | 'up' | string;
export type LazyLoadTypes = 'ondemand' | 'progressive';
@ -24,49 +27,49 @@ export interface CarouselRef {
// Carousel
export const carouselProps = () => ({
effect: String as PropType<CarouselEffect>,
dots: { type: Boolean, default: true },
vertical: { type: Boolean, default: undefined },
autoplay: { type: Boolean, default: undefined },
effect: stringType<CarouselEffect>(),
dots: booleanType(true),
vertical: booleanType(),
autoplay: booleanType(),
easing: String,
beforeChange: Function as PropType<(currentSlide: number, nextSlide: number) => void>,
afterChange: Function as PropType<(currentSlide: number) => void>,
beforeChange: functionType<(currentSlide: number, nextSlide: number) => void>(),
afterChange: functionType<(currentSlide: number) => void>(),
// style: PropTypes.React.CSSProperties,
prefixCls: String,
accessibility: { type: Boolean, default: undefined },
accessibility: booleanType(),
nextArrow: PropTypes.any,
prevArrow: PropTypes.any,
pauseOnHover: { type: Boolean, default: undefined },
pauseOnHover: booleanType(),
// className: String,
adaptiveHeight: { type: Boolean, default: undefined },
arrows: { type: Boolean, default: false },
adaptiveHeight: booleanType(),
arrows: booleanType(false),
autoplaySpeed: Number,
centerMode: { type: Boolean, default: undefined },
centerMode: booleanType(),
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 },
draggable: booleanType(false),
fade: booleanType(),
focusOnSelect: booleanType(),
infinite: booleanType(),
initialSlide: Number,
lazyLoad: String as PropType<LazyLoadTypes>,
rtl: { type: Boolean, default: undefined },
lazyLoad: stringType<LazyLoadTypes>(),
rtl: booleanType(),
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 },
swipe: booleanType(),
swipeToSlide: booleanType(),
swipeEvent: functionType<(swipeDirection: SwipeDirection) => void>(),
touchMove: booleanType(),
touchThreshold: Number,
variableWidth: { type: Boolean, default: undefined },
useCSS: { type: Boolean, default: undefined },
variableWidth: booleanType(),
useCSS: booleanType(),
slickGoTo: Number,
responsive: Array,
dotPosition: { type: String as PropType<DotPosition>, default: undefined },
verticalSwiping: { type: Boolean, default: false },
dotPosition: stringType<DotPosition>(),
verticalSwiping: booleanType(false),
});
export type CarouselProps = Partial<ExtractPropTypes<ReturnType<typeof carouselProps>>>;
const Carousel = defineComponent({
@ -104,6 +107,10 @@ const Carousel = defineComponent({
);
});
const { prefixCls, direction } = useConfigInject('carousel', props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const dotPosition = computed(() => {
if (props.dotPosition) return props.dotPosition;
if (props.vertical !== undefined) return props.vertical ? 'right' : 'bottom';
@ -122,12 +129,16 @@ const Carousel = defineComponent({
const { dots, arrows, draggable, effect } = props;
const { class: cls, style, ...restAttrs } = attrs;
const fade = effect === 'fade' ? true : props.fade;
const className = classNames(prefixCls.value, {
const className = classNames(
prefixCls.value,
{
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
[`${prefixCls.value}-vertical`]: vertical.value,
[`${cls}`]: !!cls,
});
return (
},
hashId.value,
);
return wrapSSR(
<div class={className} style={style as CSSProperties}>
<SlickCarousel
ref={slickRef}
@ -141,7 +152,7 @@ const Carousel = defineComponent({
vertical={vertical.value}
v-slots={slots}
/>
</div>
</div>,
);
};
},

View File

@ -3,7 +3,7 @@ category: Components
type: 数据展示
title: Carousel
subtitle: 走马灯
cover: https://gw.alipayobjects.com/zos/antfincdn/%24C9tmj978R/Carousel.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*bPMSSqbaTMkAAAAAAAAAAAAADrJ8AQ/original
---
旋转木马,一组轮播的区域。

View File

@ -1,294 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@carousel-prefix-cls: ~'@{ant-prefix}-carousel';
.@{carousel-prefix-cls} {
.reset-component();
.slick-slider {
position: relative;
display: block;
box-sizing: border-box;
touch-action: pan-y;
-webkit-touch-callout: none;
-webkit-tap-highlight-color: transparent;
}
.slick-list {
position: relative;
display: block;
margin: 0;
padding: 0;
overflow: hidden;
&:focus {
outline: none;
}
&.dragging {
cursor: pointer;
}
.slick-slide {
pointer-events: none;
// https://github.com/ant-design/ant-design/issues/23294
input.@{ant-prefix}-radio-input,
input.@{ant-prefix}-checkbox-input {
visibility: hidden;
}
&.slick-active {
pointer-events: auto;
input.@{ant-prefix}-radio-input,
input.@{ant-prefix}-checkbox-input {
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 {
position: relative;
top: 0;
left: 0;
display: block;
&::before,
&::after {
display: table;
content: '';
}
&::after {
clear: both;
}
.slick-loading & {
visibility: hidden;
}
}
.slick-slide {
display: none;
float: left;
height: 100%;
min-height: 1px;
img {
display: block;
}
&.slick-loading img {
display: none;
}
&.dragging img {
pointer-events: none;
}
}
.slick-initialized .slick-slide {
display: block;
}
.slick-loading .slick-slide {
visibility: hidden;
}
.slick-vertical .slick-slide {
display: block;
height: auto;
}
.slick-arrow.slick-hidden {
display: none;
}
// Arrows
.slick-prev,
.slick-next {
position: absolute;
top: 50%;
display: block;
width: 20px;
height: 20px;
margin-top: -10px;
padding: 0;
color: transparent;
font-size: 0;
line-height: 0;
background: transparent;
border: 0;
outline: none;
cursor: pointer;
&:hover,
&:focus {
color: transparent;
background: transparent;
outline: none;
&::before {
opacity: 1;
}
}
&.slick-disabled::before {
opacity: 0.25;
}
}
.slick-prev {
left: -25px;
&::before {
content: '←';
}
}
.slick-next {
right: -25px;
&::before {
content: '→';
}
}
// Dots
.slick-dots {
position: absolute;
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: 100%;
height: @carousel-dot-height;
padding: 0;
color: transparent;
font-size: 0;
background: @component-background;
border: 0;
border-radius: 1px;
outline: none;
cursor: pointer;
opacity: 0.3;
transition: all 0.5s;
&:hover,
&:focus {
opacity: 0.75;
}
}
&.slick-active {
width: @carousel-dot-active-width;
& button {
background: @component-background;
opacity: 1;
}
&:hover,
&:focus {
opacity: 1;
}
}
}
}
}
.@{ant-prefix}-carousel-vertical {
.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 {
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 {
width: @carousel-dot-height;
height: @carousel-dot-active-width;
button {
width: @carousel-dot-height;
height: @carousel-dot-active-width;
}
}
}
}
}
@import './rtl';

View File

@ -1,2 +1,350 @@
import '../../style/index.less';
import './index.less';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { resetComponent } from '../../_style';
export interface ComponentToken {
dotWidth: number;
dotHeight: number;
dotWidthActive: number;
}
interface CarouselToken extends FullToken<'Carousel'> {
carouselArrowSize: number;
carouselDotOffset: number;
carouselDotInline: number;
}
const genCarouselStyle: GenerateStyle<CarouselToken> = token => {
const { componentCls, antCls, carouselArrowSize, carouselDotOffset, marginXXS } = token;
const arrowOffset = -carouselArrowSize * 1.25;
const carouselDotMargin = marginXXS;
return {
[componentCls]: {
...resetComponent(token),
'.slick-slider': {
position: 'relative',
display: 'block',
boxSizing: 'border-box',
touchAction: 'pan-y',
WebkitTouchCallout: 'none',
WebkitTapHighlightColor: 'transparent',
'.slick-track, .slick-list': {
transform: 'translate3d(0, 0, 0)',
touchAction: 'pan-y',
},
},
'.slick-list': {
position: 'relative',
display: 'block',
margin: 0,
padding: 0,
overflow: 'hidden',
'&:focus': {
outline: 'none',
},
'&.dragging': {
cursor: 'pointer',
},
'.slick-slide': {
pointerEvents: 'none',
// https://github.com/ant-design/ant-design/issues/23294
[`input${antCls}-radio-input, input${antCls}-checkbox-input`]: {
visibility: 'hidden',
},
'&.slick-active': {
pointerEvents: 'auto',
[`input${antCls}-radio-input, input${antCls}-checkbox-input`]: {
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': {
verticalAlign: 'bottom',
},
},
},
'.slick-track': {
position: 'relative',
top: 0,
insetInlineStart: 0,
display: 'block',
'&::before, &::after': {
display: 'table',
content: '""',
},
'&::after': {
clear: 'both',
},
},
'.slick-slide': {
display: 'none',
float: 'left',
height: '100%',
minHeight: 1,
img: {
display: 'block',
},
'&.dragging img': {
pointerEvents: 'none',
},
},
'.slick-initialized .slick-slide': {
display: 'block',
},
'.slick-vertical .slick-slide': {
display: 'block',
height: 'auto',
},
'.slick-arrow.slick-hidden': {
display: 'none',
},
// Arrows
'.slick-prev, .slick-next': {
position: 'absolute',
top: '50%',
display: 'block',
width: carouselArrowSize,
height: carouselArrowSize,
marginTop: -carouselArrowSize / 2,
padding: 0,
color: 'transparent',
fontSize: 0,
lineHeight: 0,
background: 'transparent',
border: 0,
outline: 'none',
cursor: 'pointer',
'&:hover, &:focus': {
color: 'transparent',
background: 'transparent',
outline: 'none',
'&::before': {
opacity: 1,
},
},
'&.slick-disabled::before': {
opacity: 0.25,
},
},
'.slick-prev': {
insetInlineStart: arrowOffset,
'&::before': {
content: '"←"',
},
},
'.slick-next': {
insetInlineEnd: arrowOffset,
'&::before': {
content: '"→"',
},
},
// Dots
'.slick-dots': {
position: 'absolute',
insetInlineEnd: 0,
bottom: 0,
insetInlineStart: 0,
zIndex: 15,
display: 'flex !important',
justifyContent: 'center',
paddingInlineStart: 0,
listStyle: 'none',
'&-bottom': {
bottom: carouselDotOffset,
},
'&-top': {
top: carouselDotOffset,
bottom: 'auto',
},
li: {
position: 'relative',
display: 'inline-block',
flex: '0 1 auto',
boxSizing: 'content-box',
width: token.dotWidth,
height: token.dotHeight,
marginInline: carouselDotMargin,
padding: 0,
textAlign: 'center',
textIndent: -999,
verticalAlign: 'top',
transition: `all ${token.motionDurationSlow}`,
button: {
position: 'relative',
display: 'block',
width: '100%',
height: token.dotHeight,
padding: 0,
color: 'transparent',
fontSize: 0,
background: token.colorBgContainer,
border: 0,
borderRadius: 1,
outline: 'none',
cursor: 'pointer',
opacity: 0.3,
transition: `all ${token.motionDurationSlow}`,
'&: hover, &:focus': {
opacity: 0.75,
},
'&::after': {
position: 'absolute',
inset: -carouselDotMargin,
content: '""',
},
},
'&.slick-active': {
width: token.dotWidthActive,
'& button': {
background: token.colorBgContainer,
opacity: 1,
},
'&: hover, &:focus': {
opacity: 1,
},
},
},
},
},
};
};
const genCarouselVerticalStyle: GenerateStyle<CarouselToken> = token => {
const { componentCls, carouselDotOffset, marginXXS } = token;
const reverseSizeOfDot = {
width: token.dotHeight,
height: token.dotWidth,
};
return {
[`${componentCls}-vertical`]: {
'.slick-dots': {
top: '50%',
bottom: 'auto',
flexDirection: 'column',
width: token.dotHeight,
height: 'auto',
margin: 0,
transform: 'translateY(-50%)',
'&-left': {
insetInlineEnd: 'auto',
insetInlineStart: carouselDotOffset,
},
'&-right': {
insetInlineEnd: carouselDotOffset,
insetInlineStart: 'auto',
},
li: {
// reverse width and height in vertical situation
...reverseSizeOfDot,
margin: `${marginXXS}px 0`,
verticalAlign: 'baseline',
button: reverseSizeOfDot,
'&.slick-active': {
...reverseSizeOfDot,
button: reverseSizeOfDot,
},
},
},
},
};
};
const genCarouselRtlStyle: GenerateStyle<CarouselToken> = token => {
const { componentCls } = token;
return [
{
[`${componentCls}-rtl`]: {
direction: 'rtl',
// Dots
'.slick-dots': {
[`${componentCls}-rtl&`]: {
flexDirection: 'row-reverse',
},
},
},
},
{
[`${componentCls}-vertical`]: {
'.slick-dots': {
[`${componentCls}-rtl&`]: {
flexDirection: 'column',
},
},
},
},
];
};
// ============================== Export ==============================
export default genComponentStyleHook(
'Carousel',
token => {
const { controlHeightLG, controlHeightSM } = token;
const carouselToken = mergeToken<CarouselToken>(token, {
carouselArrowSize: controlHeightLG / 2,
carouselDotOffset: controlHeightSM / 2,
});
return [
genCarouselStyle(carouselToken),
genCarouselVerticalStyle(carouselToken),
genCarouselRtlStyle(carouselToken),
];
},
{
dotWidth: 16,
dotHeight: 3,
dotWidthActive: 24,
},
);

View File

@ -1,54 +0,0 @@
@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;
}
}
}

View File

@ -19,7 +19,7 @@ import './mentions/style';
// import './divider/style';
// import './card/style';
import './collapse/style';
import './carousel/style';
// import './carousel/style';
// import './notification/style';
// import './message/style';
// import './spin/style';

View File

@ -6,7 +6,7 @@ import type { ComponentToken as ButtonComponentToken } from '../../button/style'
// import type { ComponentToken as FloatButtonComponentToken } from '../../float-button/style';
// import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
import type { ComponentToken as CardComponentToken } from '../../card/style';
// import type { ComponentToken as CarouselComponentToken } from '../../carousel/style';
import type { ComponentToken as CarouselComponentToken } from '../../carousel/style';
// import type { ComponentToken as CascaderComponentToken } from '../../cascader/style';
// import type { ComponentToken as CheckboxComponentToken } from '../../checkbox/style';
// import type { ComponentToken as CollapseComponentToken } from '../../collapse/style';
@ -60,7 +60,7 @@ export interface ComponentTokenMap {
Button?: ButtonComponentToken;
Breadcrumb?: {};
Card?: CardComponentToken;
// Carousel?: CarouselComponentToken;
Carousel?: CarouselComponentToken;
// Cascader?: CascaderComponentToken;
// Checkbox?: CheckboxComponentToken;
// Collapse?: CollapseComponentToken;