refactor:timeline (#6263)

* refactor:timeline

* docs:update & refactor: timeline type
pull/6265/head^2
果冻橙 2023-02-15 13:52:47 +08:00 committed by GitHub
parent 8a233d7c3a
commit 587c1ca89d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 273 additions and 341 deletions

View File

@ -39,7 +39,7 @@ import './calendar/style';
// import './slider/style'; // import './slider/style';
import './table/style'; import './table/style';
// import './progress/style'; // import './progress/style';
import './timeline/style'; // import './timeline/style';
import './input-number/style'; import './input-number/style';
// import './transfer/style'; // import './transfer/style';
import './tree/style'; import './tree/style';

View File

@ -40,7 +40,7 @@ import type { ComponentToken as SpinComponentToken } from '../../spin/style';
// import type { ComponentToken as TableComponentToken } from '../../table/style'; // import type { ComponentToken as TableComponentToken } from '../../table/style';
// import type { ComponentToken as TabsComponentToken } from '../../tabs/style'; // import type { ComponentToken as TabsComponentToken } from '../../tabs/style';
import type { ComponentToken as TagComponentToken } from '../../tag/style'; import type { ComponentToken as TagComponentToken } from '../../tag/style';
// import type { ComponentToken as TimelineComponentToken } from '../../timeline/style'; import type { ComponentToken as TimelineComponentToken } from '../../timeline/style';
import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style'; import type { ComponentToken as TooltipComponentToken } from '../../tooltip/style';
import type { ComponentToken as TransferComponentToken } from '../../transfer/style'; import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
import type { ComponentToken as TypographyComponentToken } from '../../typography/style'; import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
@ -99,7 +99,7 @@ export interface ComponentTokenMap {
Tree?: {}; Tree?: {};
TreeSelect?: {}; TreeSelect?: {};
Typography?: TypographyComponentToken; Typography?: TypographyComponentToken;
// Timeline?: TimelineComponentToken; Timeline?: TimelineComponentToken;
Transfer?: TransferComponentToken; Transfer?: TransferComponentToken;
// Tabs?: TabsComponentToken; // Tabs?: TabsComponentToken;
// Calendar?: CalendarComponentToken; // Calendar?: CalendarComponentToken;

View File

@ -6,15 +6,18 @@ import { filterEmpty } from '../_util/props-util';
import initDefaultProps from '../_util/props-util/initDefaultProps'; import initDefaultProps from '../_util/props-util/initDefaultProps';
import TimelineItem from './TimelineItem'; import TimelineItem from './TimelineItem';
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined'; import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
import { tuple } from '../_util/type'; import { tuple, booleanType } from '../_util/type';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
// CSSINJS
import useStyle from './style';
export const timelineProps = () => ({ export const timelineProps = () => ({
prefixCls: String, prefixCls: String,
/** 指定最后一个幽灵节点是否存在或内容 */ /** 指定最后一个幽灵节点是否存在或内容 */
pending: PropTypes.any, pending: PropTypes.any,
pendingDot: PropTypes.any, pendingDot: PropTypes.any,
reverse: { type: Boolean, default: undefined }, reverse: booleanType(),
mode: PropTypes.oneOf(tuple('left', 'alternate', 'right', '')), mode: PropTypes.oneOf(tuple('left', 'alternate', 'right', '')),
}); });
@ -23,13 +26,18 @@ export type TimelineProps = Partial<ExtractPropTypes<ReturnType<typeof timelineP
export default defineComponent({ export default defineComponent({
compatConfig: { MODE: 3 }, compatConfig: { MODE: 3 },
name: 'ATimeline', name: 'ATimeline',
inheritAttrs: false,
props: initDefaultProps(timelineProps(), { props: initDefaultProps(timelineProps(), {
reverse: false, reverse: false,
mode: '', mode: '',
}), }),
slots: ['pending', 'pendingDot'], slots: ['pending', 'pendingDot'],
setup(props, { slots }) { setup(props, { slots, attrs }) {
const { prefixCls, direction } = useConfigInject('timeline', props); const { prefixCls, direction } = useConfigInject('timeline', props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const getPositionCls = (ele, idx: number) => { const getPositionCls = (ele, idx: number) => {
const eleProps = ele.props || {}; const eleProps = ele.props || {};
if (props.mode === 'alternate') { if (props.mode === 'alternate') {
@ -80,14 +88,23 @@ export default defineComponent({
const hasLabelItem = timeLineItems.some( const hasLabelItem = timeLineItems.some(
item => !!(item.props?.label || item.children?.label), item => !!(item.props?.label || item.children?.label),
); );
const classString = classNames(prefixCls.value, { const classString = classNames(
prefixCls.value,
{
[`${prefixCls.value}-pending`]: !!pending, [`${prefixCls.value}-pending`]: !!pending,
[`${prefixCls.value}-reverse`]: !!reverse, [`${prefixCls.value}-reverse`]: !!reverse,
[`${prefixCls.value}-${mode}`]: !!mode && !hasLabelItem, [`${prefixCls.value}-${mode}`]: !!mode && !hasLabelItem,
[`${prefixCls.value}-label`]: hasLabelItem, [`${prefixCls.value}-label`]: hasLabelItem,
[`${prefixCls.value}-rtl`]: direction.value === 'rtl', [`${prefixCls.value}-rtl`]: direction.value === 'rtl',
}); },
return <ul class={classString}>{items}</ul>; attrs.class,
hashId.value,
);
return wrapSSR(
<ul {...attrs} class={classString}>
{items}
</ul>,
);
}; };
}, },
}); });

View File

@ -3,14 +3,14 @@ import { defineComponent } from 'vue';
import classNames from '../_util/classNames'; import classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types'; import PropTypes from '../_util/vue-types';
import initDefaultProps from '../_util/props-util/initDefaultProps'; import initDefaultProps from '../_util/props-util/initDefaultProps';
import { tuple } from '../_util/type'; import { tuple, booleanType } from '../_util/type';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
export const timelineItemProps = () => ({ export const timelineItemProps = () => ({
prefixCls: String, prefixCls: String,
color: String, color: String,
dot: PropTypes.any, dot: PropTypes.any,
pending: { type: Boolean, default: undefined }, pending: booleanType(),
position: PropTypes.oneOf(tuple('left', 'right', '')).def(''), position: PropTypes.oneOf(tuple('left', 'right', '')).def(''),
label: PropTypes.any, label: PropTypes.any,
}); });

View File

@ -2,7 +2,7 @@
category: Components category: Components
type: Data Display type: Data Display
title: Timeline title: Timeline
cover: https://gw.alipayobjects.com/zos/antfincdn/vJmo00mmgR/Timeline.svg cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*FkTySqNt3sYAAAAAAAAAAAAADrJ8AQ/original
--- ---
Vertical display timeline. Vertical display timeline.

View File

@ -3,7 +3,7 @@ category: Components
type: 数据展示 type: 数据展示
title: Timeline title: Timeline
subtitle: 时间轴 subtitle: 时间轴
cover: https://gw.alipayobjects.com/zos/antfincdn/vJmo00mmgR/Timeline.svg cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*FkTySqNt3sYAAAAAAAAAAAAADrJ8AQ/original
--- ---
垂直展示的时间流信息。 垂直展示的时间流信息。

View File

@ -1,185 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@timeline-prefix-cls: ~'@{ant-prefix}-timeline';
.@{timeline-prefix-cls} {
.reset-component();
margin: 0;
padding: 0;
list-style: none;
&-item {
position: relative;
margin: 0;
padding-bottom: @timeline-item-padding-bottom;
font-size: @font-size-base;
list-style: none;
&-tail {
position: absolute;
top: 10px;
left: 4px;
height: calc(100% - 10px);
border-left: @timeline-width solid @timeline-color;
}
&-pending &-head {
font-size: @font-size-sm;
background-color: transparent;
}
&-pending &-tail {
display: none;
}
&-head {
position: absolute;
width: 10px;
height: 10px;
background-color: @timeline-dot-bg;
border: @timeline-dot-border-width solid transparent;
border-radius: 100px;
&-blue {
color: @primary-color;
border-color: @primary-color;
}
&-red {
color: @error-color;
border-color: @error-color;
}
&-green {
color: @success-color;
border-color: @success-color;
}
&-gray {
color: @disabled-color;
border-color: @disabled-color;
}
}
&-head-custom {
position: absolute;
top: 5.5px;
left: 5px;
width: auto;
height: auto;
margin-top: 0;
padding: 3px 1px;
line-height: 1;
text-align: center;
border: 0;
border-radius: 0;
transform: translate(-50%, -50%);
}
&-content {
position: relative;
top: -(@font-size-base * @line-height-base - @font-size-base) + 1px;
margin: 0 0 0 @margin-lg + 2px;
word-break: break-word;
}
&-last {
> .@{timeline-prefix-cls}-item-tail {
display: none;
}
> .@{timeline-prefix-cls}-item-content {
min-height: 48px;
}
}
}
&.@{timeline-prefix-cls}-alternate,
&.@{timeline-prefix-cls}-right,
&.@{timeline-prefix-cls}-label {
.@{timeline-prefix-cls}-item {
&-tail,
&-head,
&-head-custom {
left: 50%;
}
&-head {
margin-left: -4px;
&-custom {
margin-left: 1px;
}
}
&-left {
.@{timeline-prefix-cls}-item-content {
left: calc(50% - 4px);
width: calc(50% - 14px);
text-align: left;
}
}
&-right {
.@{timeline-prefix-cls}-item-content {
width: calc(50% - 12px);
margin: 0;
text-align: right;
}
}
}
}
&.@{timeline-prefix-cls}-right {
.@{timeline-prefix-cls}-item-right {
.@{timeline-prefix-cls}-item-tail,
.@{timeline-prefix-cls}-item-head,
.@{timeline-prefix-cls}-item-head-custom {
left: calc(100% - 4px - @timeline-width);
}
.@{timeline-prefix-cls}-item-content {
width: calc(100% - 18px);
}
}
}
&&-pending &-item-last &-item-tail {
display: block;
height: calc(100% - 14px);
border-left: 2px dotted @timeline-color;
}
&&-reverse &-item-last &-item-tail {
display: none;
}
&&-reverse &-item-pending {
.@{timeline-prefix-cls}-item-tail {
top: 15px;
display: block;
height: calc(100% - 15px);
border-left: 2px dotted @timeline-color;
}
.@{timeline-prefix-cls}-item-content {
min-height: 48px;
}
}
&.@{timeline-prefix-cls}-label {
.@{timeline-prefix-cls}-item-label {
position: absolute;
top: -(@font-size-base * @line-height-base - @font-size-base) + 1px;
width: calc(50% - 12px);
text-align: right;
}
.@{timeline-prefix-cls}-item-right {
.@{timeline-prefix-cls}-item-label {
left: calc(50% + 14px);
width: calc(50% - 14px);
text-align: left;
}
}
}
}
@import './rtl';

View File

@ -1,2 +1,237 @@
import '../../style/index.less'; import type { CSSObject } from '../../_util/cssinjs';
import './index.less'; import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { resetComponent } from '../../_style';
export interface ComponentToken {}
interface TimelineToken extends FullToken<'Timeline'> {
timeLineItemPaddingBottom: number;
timeLineItemHeadSize: number;
timeLineItemCustomHeadPaddingVertical: number;
timeLineItemTailWidth: number;
timeLinePaddingInlineEnd: number;
timeLineHeadBorderWidth: number;
}
const genTimelineStyle: GenerateStyle<TimelineToken, CSSObject> = token => {
const { componentCls } = token;
return {
[componentCls]: {
...resetComponent(token),
margin: 0,
padding: 0,
listStyle: 'none',
[`${componentCls}-item`]: {
position: 'relative',
margin: 0,
paddingBottom: token.timeLineItemPaddingBottom,
fontSize: token.fontSize,
listStyle: 'none',
'&-tail': {
position: 'absolute',
insetBlockStart: token.timeLineItemHeadSize,
insetInlineStart: (token.timeLineItemHeadSize - token.timeLineItemTailWidth) / 2,
height: `calc(100% - ${token.timeLineItemHeadSize}px)`,
borderInlineStart: `${token.timeLineItemTailWidth}px ${token.lineType} ${token.colorSplit}`,
},
'&-pending': {
[`${componentCls}-item-head`]: {
fontSize: token.fontSizeSM,
backgroundColor: 'transparent',
},
[`${componentCls}-item-tail`]: {
display: 'none',
},
},
'&-head': {
position: 'absolute',
width: token.timeLineItemHeadSize,
height: token.timeLineItemHeadSize,
backgroundColor: token.colorBgContainer,
border: `${token.timeLineHeadBorderWidth}px ${token.lineType} transparent`,
borderRadius: '50%',
'&-blue': {
color: token.colorPrimary,
borderColor: token.colorPrimary,
},
'&-red': {
color: token.colorError,
borderColor: token.colorError,
},
'&-green': {
color: token.colorSuccess,
borderColor: token.colorSuccess,
},
'&-gray': {
color: token.colorTextDisabled,
borderColor: token.colorTextDisabled,
},
},
'&-head-custom': {
position: 'absolute',
insetBlockStart: token.timeLineItemHeadSize / 2,
insetInlineStart: token.timeLineItemHeadSize / 2,
width: 'auto',
height: 'auto',
marginBlockStart: 0,
paddingBlock: token.timeLineItemCustomHeadPaddingVertical,
lineHeight: 1,
textAlign: 'center',
border: 0,
borderRadius: 0,
transform: `translate(-50%, -50%)`,
},
'&-content': {
position: 'relative',
insetBlockStart: -(token.fontSize * token.lineHeight - token.fontSize) + token.lineWidth,
marginInlineStart: token.margin + token.timeLineItemHeadSize,
marginInlineEnd: 0,
marginBlockStart: 0,
marginBlockEnd: 0,
wordBreak: 'break-word',
},
'&-last': {
[`> ${componentCls}-item-tail`]: {
display: 'none',
},
[`> ${componentCls}-item-content`]: {
minHeight: token.controlHeightLG * 1.2,
},
},
},
[`&${componentCls}-alternate,
&${componentCls}-right,
&${componentCls}-label`]: {
[`${componentCls}-item`]: {
'&-tail, &-head, &-head-custom': {
insetInlineStart: '50%',
},
'&-head': {
marginInlineStart: `-${token.marginXXS}px`,
'&-custom': {
marginInlineStart: token.timeLineItemTailWidth / 2,
},
},
'&-left': {
[`${componentCls}-item-content`]: {
insetInlineStart: `calc(50% - ${token.marginXXS}px)`,
width: `calc(50% - ${token.marginSM}px)`,
textAlign: 'start',
},
},
'&-right': {
[`${componentCls}-item-content`]: {
width: `calc(50% - ${token.marginSM}px)`,
margin: 0,
textAlign: 'end',
},
},
},
},
[`&${componentCls}-right`]: {
[`${componentCls}-item-right`]: {
[`${componentCls}-item-tail,
${componentCls}-item-head,
${componentCls}-item-head-custom`]: {
insetInlineStart: `calc(100% - ${
(token.timeLineItemHeadSize + token.timeLineItemTailWidth) / 2
}px)`,
},
[`${componentCls}-item-content`]: {
width: `calc(100% - ${token.timeLineItemHeadSize + token.marginXS}px)`,
},
},
},
[`&${componentCls}-pending
${componentCls}-item-last
${componentCls}-item-tail`]: {
display: 'block',
height: `calc(100% - ${token.margin}px)`,
borderInlineStart: `${token.timeLineItemTailWidth}px dotted ${token.colorSplit}`,
},
[`&${componentCls}-reverse
${componentCls}-item-last
${componentCls}-item-tail`]: {
display: 'none',
},
[`&${componentCls}-reverse ${componentCls}-item-pending`]: {
[`${componentCls}-item-tail`]: {
insetBlockStart: token.margin,
display: 'block',
height: `calc(100% - ${token.margin}px)`,
borderInlineStart: `${token.timeLineItemTailWidth}px dotted ${token.colorSplit}`,
},
[`${componentCls}-item-content`]: {
minHeight: token.controlHeightLG * 1.2,
},
},
[`&${componentCls}-label`]: {
[`${componentCls}-item-label`]: {
position: 'absolute',
insetBlockStart:
-(token.fontSize * token.lineHeight - token.fontSize) + token.timeLineItemTailWidth,
width: `calc(50% - ${token.marginSM}px)`,
textAlign: 'end',
},
[`${componentCls}-item-right`]: {
[`${componentCls}-item-label`]: {
insetInlineStart: `calc(50% + ${token.marginSM}px)`,
width: `calc(50% - ${token.marginSM}px)`,
textAlign: 'start',
},
},
},
// ====================== RTL =======================
'&-rtl': {
direction: 'rtl',
[`${componentCls}-item-head-custom`]: {
transform: `translate(50%, -50%)`,
},
},
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('Timeline', token => {
const timeLineToken = mergeToken<TimelineToken>(token, {
timeLineItemPaddingBottom: token.padding * 1.25,
timeLineItemHeadSize: 10,
timeLineItemCustomHeadPaddingVertical: token.paddingXXS,
timeLinePaddingInlineEnd: 2,
timeLineItemTailWidth: token.lineWidthBold,
timeLineHeadBorderWidth: token.wireframe ? token.lineWidthBold : token.lineWidth * 3,
});
return [genTimelineStyle(timeLineToken)];
});

View File

@ -1,135 +0,0 @@
@import '../../style/themes/index';
@import '../../style/mixins/index';
@timeline-prefix-cls: ~'@{ant-prefix}-timeline';
.@{timeline-prefix-cls} {
&-rtl {
direction: rtl;
}
&-item {
&-tail {
.@{timeline-prefix-cls}-rtl & {
right: 4px;
left: auto;
border-right: @timeline-width solid @timeline-color;
border-left: none;
}
}
&-head-custom {
.@{timeline-prefix-cls}-rtl & {
right: 5px;
left: auto;
transform: translate(50%, -50%);
}
}
&-content {
.@{timeline-prefix-cls}-rtl & {
margin: 0 18px 0 0;
}
}
}
&.@{timeline-prefix-cls}-alternate,
&.@{timeline-prefix-cls}-right,
&.@{timeline-prefix-cls}-label {
.@{timeline-prefix-cls}-item {
&-tail,
&-head,
&-head-custom {
.@{timeline-prefix-cls}-rtl& {
right: 50%;
left: auto;
}
}
&-head {
.@{timeline-prefix-cls}-rtl& {
margin-right: -4px;
margin-left: 0;
}
&-custom {
.@{timeline-prefix-cls}-rtl& {
margin-right: 1px;
margin-left: 0;
}
}
}
&-left {
.@{timeline-prefix-cls}-item-content {
.@{timeline-prefix-cls}-rtl& {
right: calc(50% - 4px);
left: auto;
text-align: right;
}
}
}
&-right {
.@{timeline-prefix-cls}-item-content {
.@{timeline-prefix-cls}-rtl& {
text-align: left;
}
}
}
}
}
&.@{timeline-prefix-cls}-right {
.@{timeline-prefix-cls}-item-right {
.@{timeline-prefix-cls}-item-tail,
.@{timeline-prefix-cls}-item-head,
.@{timeline-prefix-cls}-item-head-custom {
.@{timeline-prefix-cls}-rtl& {
right: 0;
left: auto;
}
}
.@{timeline-prefix-cls}-item-content {
.@{timeline-prefix-cls}-rtl& {
width: 100%;
margin-right: 18px;
text-align: right;
}
}
}
}
&&-pending &-item-last &-item-tail {
.@{timeline-prefix-cls}-rtl& {
border-right: 2px dotted @timeline-color;
border-left: none;
}
}
&&-reverse &-item-pending {
.@{timeline-prefix-cls}-item-tail {
.@{timeline-prefix-cls}-rtl& {
border-right: 2px dotted @timeline-color;
border-left: none;
}
}
}
&.@{timeline-prefix-cls}-label {
.@{timeline-prefix-cls}-item-label {
.@{timeline-prefix-cls}-rtl& {
text-align: left;
}
}
.@{timeline-prefix-cls}-item-right {
.@{timeline-prefix-cls}-item-label {
.@{timeline-prefix-cls}-rtl& {
right: calc(50% + 14px);
text-align: right;
}
}
}
}
}