diff --git a/site/site.config.mjs b/site/site.config.mjs index 918e2923b6..c9624cdc56 100644 --- a/site/site.config.mjs +++ b/site/site.config.mjs @@ -397,6 +397,12 @@ export default { path: '/react/components/tag', component: () => import('tdesign-react/tag/tag.md'), }, + { + title: 'Timeline 时间轴', + name: 'timeline', + path: '/react/components/timeline', + component: () => import('tdesign-react/timeline/timeline.md'), + }, { title: 'Tooltip 文字提示', name: 'tooltip', diff --git a/src/_util/renderTNode.ts b/src/_util/renderTNode.ts index c409441efb..7c9baf2cad 100644 --- a/src/_util/renderTNode.ts +++ b/src/_util/renderTNode.ts @@ -1,14 +1,16 @@ -import React from 'react'; import { TNode } from '../common'; +type RenderType = T extends () => infer P ? P : T; + /** - * 渲染 TNode 类型节点 + * 渲染 任意 T | () => T 类型节点 + * 默认类型为TNode * @param tnode */ -export default function renderTNode(tnode: TNode, defaultNode?: React.ReactNode): React.ReactNode { +export default function renderTNode(tnode: T, defaultNode?: T): RenderType { if (typeof tnode === 'function') { return tnode(); } - return tnode || defaultNode; + return tnode || (typeof defaultNode === 'function' ? defaultNode() : defaultNode); } diff --git a/src/index.ts b/src/index.ts index 87574a4927..baa3eea5ac 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,6 +57,7 @@ export * from './watermark'; export * from './image-viewer'; export * from './space'; export * from './jumper'; +export * from './timeline'; export * from './image'; export * from './rate'; export * from './link'; diff --git a/src/timeline/Timeline.tsx b/src/timeline/Timeline.tsx new file mode 100644 index 0000000000..5aa2664ca4 --- /dev/null +++ b/src/timeline/Timeline.tsx @@ -0,0 +1,77 @@ +import classNames from 'classnames'; +import React from 'react'; +import { StyledProps } from '../common'; +import useConfig from '../hooks/useConfig'; +import TimelineItem from './TimelineItem'; +import { TdTimelineProps } from './type'; +import TimelineContext from './TimelineContext'; +import forwardRefWithStatics from '../_util/forwardRefWithStatics'; +import { useAlign } from './useAlign'; + +export interface TimelineProps extends TdTimelineProps, StyledProps { + children?: React.ReactNode; +} + +const Timeline = forwardRefWithStatics( + (props: TimelineProps, ref: React.Ref) => { + const { + theme = 'default', + labelAlign = 'left', + children, + className, + style, + reverse = false, + layout = 'vertical', + mode = 'alternate', + } = props; + const { classPrefix } = useConfig(); + const renderAlign = useAlign(labelAlign, layout); + + const timelineItems = React.Children.toArray(children).filter( + (child: JSX.Element) => child.type.displayName === TimelineItem.displayName, + ); + // 获取所有子节点类型 + const itemsStatus = React.Children.map(timelineItems, (child: JSX.Element) => child.props?.dotColor || 'primary'); + const hasLabelItem = timelineItems.some((item: React.ReactElement) => !!item?.props?.label); + + if (reverse) { + timelineItems.reverse(); + } + + const itemsCounts = React.Children.count(timelineItems); + + const timelineClassName = classNames( + `${classPrefix}-timeline`, + { + [`${classPrefix}-timeline-${renderAlign}`]: true, + [`${classPrefix}-timeline-reverse`]: reverse, + [`${classPrefix}-timeline-${layout}`]: true, + [`${classPrefix}-timeline-label`]: hasLabelItem, + [`${classPrefix}-timeline-label--${mode}`]: true, + }, + className, + ); + + return ( + +
    + {React.Children.map(timelineItems, (ele: JSX.Element, index) => + React.cloneElement(ele, { + index, + className: classNames([ele?.props?.className], { + [`${classPrefix}-timeline-item--last`]: index === itemsCounts - 1, + }), + }), + )} +
+
+ ); + }, + { + Item: TimelineItem, + }, +); + +Timeline.displayName = 'Timeline'; + +export default Timeline; diff --git a/src/timeline/TimelineContext.ts b/src/timeline/TimelineContext.ts new file mode 100644 index 0000000000..9b34b03406 --- /dev/null +++ b/src/timeline/TimelineContext.ts @@ -0,0 +1,19 @@ +import React from 'react'; +import { TdTimelineProps } from './type'; + +const StepsContext = React.createContext<{ + theme: TdTimelineProps['theme']; + reverse: TdTimelineProps['reverse']; + itemsStatus: string[]; + layout: TdTimelineProps['layout']; + globalAlign?: TdTimelineProps['labelAlign']; + mode?: TdTimelineProps['mode']; +}>({ + theme: 'default', + reverse: false, + itemsStatus: [], + layout: 'vertical', + mode: 'alternate', +}); + +export default StepsContext; diff --git a/src/timeline/TimelineItem.tsx b/src/timeline/TimelineItem.tsx new file mode 100644 index 0000000000..600be13d68 --- /dev/null +++ b/src/timeline/TimelineItem.tsx @@ -0,0 +1,112 @@ +import React, { useContext, useMemo } from 'react'; +import classNames from 'classnames'; +import { TdTimelineItemProps } from './type'; +import { StyledProps } from '../common'; +import useConfig from '../hooks/useConfig'; +import TimelineContext from './TimelineContext'; +import renderTNode from '../_util/renderTNode'; +import { useAlign } from './useAlign'; +import Loading from '../loading'; + +export interface TimelineItemProps extends TdTimelineItemProps, StyledProps { + children?: React.ReactNode; + index?: number; +} + +const DefaultTheme = ['default', 'primary', 'success', 'warning', 'error']; + +const TimelineItem: React.FC = (props) => { + const { + className, + style = {}, + dot, + dotColor = 'primary', + labelAlign, + children, + index, + content, + label, + loading = false, + } = props; + const { theme, reverse, itemsStatus, layout, globalAlign, mode } = useContext(TimelineContext); + const { classPrefix } = useConfig(); + const renderAlign = useAlign(globalAlign, layout); + + // 计算节点模式 CSS 类名 + const getPositionClassName = (index: number) => { + // 横向布局 以及 纵向布局对应为不同的样式名 + const left = layout === 'horizontal' ? 'top' : 'left'; + const right = layout === 'horizontal' ? 'bottom' : 'right'; + // 单独设置则单独生效 + if (renderAlign === 'alternate') { + return labelAlign || index % 2 === 0 + ? `${classPrefix}-timeline-item-${left}` + : `${classPrefix}-timeline-item-${right}`; + } + if (renderAlign === 'left' || renderAlign === 'top') { + return `${classPrefix}-timeline-item-${left}`; + } + if (renderAlign === 'right' || renderAlign === 'bottom') { + return `${classPrefix}-timeline-item-${right}`; + } + return ''; + }; + + const dotElement = useMemo(() => { + const ele = renderTNode(dot); + return ( + ele && + React.cloneElement(ele, { + className: classNames(ele?.props?.className, `${classPrefix}-timeline-item__dot-content`), + }) + ); + }, [dot, classPrefix]); + + // 节点类名 + const itemClassName = classNames( + { + [`${classPrefix}-timeline-item`]: true, + [`${getPositionClassName(index)}`]: true, + }, + className, + ); + + // 连线类名 + const tailClassName = classNames({ + [`${classPrefix}-timeline-item__tail`]: true, + [`${classPrefix}-timeline-item__tail--theme-${theme}`]: true, + [`${classPrefix}-timeline-item__tail--status-${itemsStatus[index]}`]: reverse, + }); + + // 圆圈类名 + const dotClassName = classNames({ + [`${classPrefix}-timeline-item__dot`]: true, + [`${classPrefix}-timeline-item__dot--custom`]: !!dotElement || (!dotElement && loading), + [`${classPrefix}-timeline-item__dot--${dotColor}`]: DefaultTheme.includes(dotColor), + }); + + const labelClassName = classNames(`${classPrefix}-timeline-item__label`, { + [`${classPrefix}-timeline-item__label--${mode}`]: true, + }); + + return ( +
  • + {mode === 'alternate' && label &&
    {label}
    } +
    +
    + {!dotElement && loading && } + {dotElement} +
    +
    +
    +
    + {content || children} + {mode === 'same' && label &&
    {label}
    } +
    +
  • + ); +}; + +TimelineItem.displayName = 'TimelineItem'; + +export default TimelineItem; diff --git a/src/timeline/__tests__/__snapshots__/timeline.test.tsx.snap b/src/timeline/__tests__/__snapshots__/timeline.test.tsx.snap new file mode 100644 index 0000000000..1ccba3f712 --- /dev/null +++ b/src/timeline/__tests__/__snapshots__/timeline.test.tsx.snap @@ -0,0 +1,1299 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`base.tsx 1`] = ` + +
    +
    +
    +
    +

    + 时间轴方向 +

    +
    +
    +
    + + +
    +
    +
    +
    +
    +
      +
    • +
      +
      +
      +
      +
      + 事件一 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件二 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件三 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件四 +
      + 2022-04-01 +
      +
      +
    • +
    +
    +
    +
    +`; + +exports[`customContent.tsx 1`] = ` + +
      +
    • +
      +
      +
      +
      +
      +
      + 事件一 +
      +
      + 事件一自定义内容 +
      +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      +
      + 事件二 +
      +
      + 事件二自定义内容 +
      +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      +
      + 事件三 +
      +
      + 事件三自定义内容 +
      +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      +
      + 事件四 +
      +
      + 事件四自定义内容 +
      +
      + 2022-04-01 +
      +
      +
    • +
    +
    +`; + +exports[`customDot.tsx 1`] = ` + +
    +
    +
    +
    +

    + 时间轴样式 +

    +
    +
    +
    + + +
    +
    +
    +
    +
    +
      +
    • +
      +
      + + + +
      +
      +
      +
      + 事件一 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      + + + +
      +
      +
      +
      + 事件二 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      + + + +
      +
      +
      +
      + 事件三 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      + + + + +
      +
      +
      +
      + 事件四 +
      + 2022-04-01 +
      +
      +
    • +
    +
    +
    +
    +`; + +exports[`layout.tsx 1`] = ` + +
    +
    +
    +
    +

    + 时间轴方向 +

    +
    +
    +
    + + +
    +
    +
    +
    +
    +
    +
    +

    + 对齐方式 +

    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +

    + label对齐方式 +

    +
    +
    +
    + + +
    +
    +
    +
    +
    +
      +
    • +
      +
      +
      +
      +
      + 事件一 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件二 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件三 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件四 +
      + 2022-04-01 +
      +
      +
    • +
    +
    +
    +
    +`; + +exports[`loading.tsx 1`] = ` + +
    +
    +
    +
    +

    + 加载中 +

    +
    +
    + +
    +
    +
    +
    +
      +
    • +
      +
      +
      +
      +
      + 事件一 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件二 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件三 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件四 +
      + 2022-04-01 +
      +
      +
    • +
    +
    +
    +
    +`; + +exports[`reverse.tsx 1`] = ` + +
    +
    +
    +
    +

    + 是否倒序 +

    +
    +
    + +
    +
    +
    +
    +
      +
    • +
      +
      +
      +
      +
      + 事件一 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件二 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件三 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 事件四 +
      + 2022-04-01 +
      +
      +
    • +
    +
    +
    +
    +`; + +exports[`theme.tsx 1`] = ` + +
      +
    • +
      +
      +
      +
      +
      + 已完成的时间 +
      + 2022-01-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 成功的时间 +
      + 2022-02-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 危险时间 +
      + 2022-03-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 告警事件 +
      + 2022-04-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 默认的时间 +
      + 2022-05-01 +
      +
      +
    • +
    • +
      +
      +
      +
      +
      + 自定义主题色 +
      + 2022-06-01 +
      +
      +
    • +
    +
    +`; diff --git a/src/timeline/__tests__/timeline.test.tsx b/src/timeline/__tests__/timeline.test.tsx new file mode 100644 index 0000000000..5b4e80e854 --- /dev/null +++ b/src/timeline/__tests__/timeline.test.tsx @@ -0,0 +1,4 @@ +import { testExamples } from '@test/utils'; + +// 测试组件代码 Example 快照 +testExamples(__dirname); diff --git a/src/timeline/_example/base.tsx b/src/timeline/_example/base.tsx new file mode 100644 index 0000000000..55e6e01b87 --- /dev/null +++ b/src/timeline/_example/base.tsx @@ -0,0 +1,24 @@ +import React, { useState } from 'react'; +import { Timeline, Space, Radio } from 'tdesign-react'; + +export default function BasicTimeLine() { + const [direction, setDirection] = useState<'vertical' | 'horizontal'>('vertical'); + + return ( + + +

    时间轴方向

    + setDirection(v as any)}> + 垂直时间轴 + 水平时间轴 + +
    + + 事件一 + 事件二 + 事件三 + 事件四 + +
    + ); +} diff --git a/src/timeline/_example/customContent.tsx b/src/timeline/_example/customContent.tsx new file mode 100644 index 0000000000..a80b4aeab6 --- /dev/null +++ b/src/timeline/_example/customContent.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Timeline } from 'tdesign-react'; + +const CommonStyle = { + fontSize: 12, + color: 'rgba(0,0,0,.6)', +}; + +export default function CustomContentTimeLine() { + return ( + + +
    事件一
    +
    事件一自定义内容
    +
    + +
    事件二
    +
    事件二自定义内容
    +
    + +
    事件三
    +
    事件三自定义内容
    +
    + +
    事件四
    +
    事件四自定义内容
    +
    +
    + ); +} diff --git a/src/timeline/_example/customDot.tsx b/src/timeline/_example/customDot.tsx new file mode 100644 index 0000000000..6e215cf8f4 --- /dev/null +++ b/src/timeline/_example/customDot.tsx @@ -0,0 +1,35 @@ +import React, { useState } from 'react'; +import { Timeline, Space, Radio } from 'tdesign-react'; +import { TipsIcon, UserIcon, HeartIcon, HomeIcon } from 'tdesign-icons-react'; + +const color = 'var(--td-brand-color)'; + +export default function CustomDotTimeLine() { + const [dot, setDot] = useState<'default' | 'dot'>('default'); + + return ( + + +

    时间轴样式

    + setDot(v as any)}> + 默认样式 + Dot样式 + +
    + + }> + 事件一 + + }> + 事件二 + + }> + 事件三 + + }> + 事件四 + + +
    + ); +} diff --git a/src/timeline/_example/layout.tsx b/src/timeline/_example/layout.tsx new file mode 100644 index 0000000000..489eda4c9d --- /dev/null +++ b/src/timeline/_example/layout.tsx @@ -0,0 +1,41 @@ +import React, { useState } from 'react'; +import { Timeline, Space, Radio } from 'tdesign-react'; + +export default function LayoutTimeLine() { + const [direction, setDirection] = useState<'left' | 'right' | 'alternate'>('left'); + const [mode, setMode] = useState<'same' | 'alternate'>('same'); + const [layout, setLayout] = useState<'vertical' | 'horizontal'>('vertical'); + + return ( + + +

    时间轴方向

    + setLayout(v as any)}> + 垂直时间轴 + 水平时间轴 + +
    + +

    对齐方式

    + setDirection(v as any)}> + 左对齐 + 交错对齐 + 右对齐 + +
    + +

    label对齐方式

    + setMode(v as any)}> + 同侧 + 交错 + +
    + + 事件一 + 事件二 + 事件三 + 事件四 + +
    + ); +} diff --git a/src/timeline/_example/loading.tsx b/src/timeline/_example/loading.tsx new file mode 100644 index 0000000000..6e25c82253 --- /dev/null +++ b/src/timeline/_example/loading.tsx @@ -0,0 +1,23 @@ +import React, { useState } from 'react'; +import { Timeline, Space, Switch } from 'tdesign-react'; + +export default function LoadingTimeLine() { + const [loading, setLoading] = useState(false); + + return ( + + +

    加载中

    + setLoading(v as boolean)}> +
    + + 事件一 + 事件二 + 事件三 + + 事件四 + + +
    + ); +} diff --git a/src/timeline/_example/reverse.tsx b/src/timeline/_example/reverse.tsx new file mode 100644 index 0000000000..0c6853b748 --- /dev/null +++ b/src/timeline/_example/reverse.tsx @@ -0,0 +1,21 @@ +import React, { useState } from 'react'; +import { Timeline, Space, Switch } from 'tdesign-react'; + +export default function ReverseTimeLine() { + const [reverse, setReverse] = useState(false); + + return ( + + +

    是否倒序

    + setReverse(v as boolean)}> +
    + + 事件一 + 事件二 + 事件三 + 事件四 + +
    + ); +} diff --git a/src/timeline/_example/theme.tsx b/src/timeline/_example/theme.tsx new file mode 100644 index 0000000000..9f5642d184 --- /dev/null +++ b/src/timeline/_example/theme.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { Timeline } from 'tdesign-react'; + +export default function ThemeTimeLine() { + return ( + + + 已完成的时间 + + + 成功的时间 + + + 危险时间 + + + 告警事件 + + 默认的时间 + + 自定义主题色 + + + ); +} diff --git a/src/timeline/defaultProps.ts b/src/timeline/defaultProps.ts new file mode 100644 index 0000000000..ec10cdd4a7 --- /dev/null +++ b/src/timeline/defaultProps.ts @@ -0,0 +1,15 @@ +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TdTimelineProps, TdTimelineItemProps } from './type'; + +export const timeLineDefaultProps: TdTimelineProps = { + labelAlign: 'right', + layout: 'vertical', + mode: 'alternate', + reverse: false, + theme: 'default', +}; + +export const timeLineItemDefaultProps: TdTimelineItemProps = { dotColor: 'default' }; diff --git a/src/timeline/index.ts b/src/timeline/index.ts new file mode 100644 index 0000000000..3789e667e0 --- /dev/null +++ b/src/timeline/index.ts @@ -0,0 +1,9 @@ +import _Timeline from './Timeline'; + +import './style/index.js'; + +export type { TimelineProps } from './Timeline'; + +export const Timeline = _Timeline; + +export default Timeline; diff --git a/src/timeline/style/css.js b/src/timeline/style/css.js new file mode 100644 index 0000000000..6a9a4b1328 --- /dev/null +++ b/src/timeline/style/css.js @@ -0,0 +1 @@ +import './index.css'; diff --git a/src/timeline/style/index.js b/src/timeline/style/index.js new file mode 100644 index 0000000000..1c112d2820 --- /dev/null +++ b/src/timeline/style/index.js @@ -0,0 +1 @@ +import '../../_common/style/web/components/timeline/_index.less'; diff --git a/src/timeline/timeline.md b/src/timeline/timeline.md new file mode 100644 index 0000000000..ce4061182b --- /dev/null +++ b/src/timeline/timeline.md @@ -0,0 +1,28 @@ +:: BASE_DOC :: + +## API + +### Timeline Props + +名称 | 类型 | 默认值 | 说明 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +labelAlign | String | right | 标签信息放在时间轴的位置,`mode='alternate'` 时生效。纵向时间轴信息位置:左侧、右侧或两侧,默认信息在时间轴右侧。横向时间轴信息位置:上方、下方、两侧。可选项:left/right/alternate/top/bottom | N +layout | String | vertical | 时间轴方向:水平方向、垂直方向。可选项:horizontal/vertical | N +mode | String | alternate | 标签与内容文本的位置关系,`alternate` 为展示在轴两侧,`same` 为展示在同一侧。可选项:alternate/same | N +reverse | Boolean | false | 时间轴是否表现为倒序 | N +theme | String | default | 步骤条风格。可选项:default/dot | N + +### TimelineItem Props + +名称 | 类型 | 默认值 | 说明 | 必传 +-- | -- | -- | -- | -- +className | String | - | 类名 | N +style | Object | - | 样式,TS 类型:`React.CSSProperties` | N +children | TNode | - | 描述内容,同 content。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +content | TNode | - | 描述内容。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +dot | TElement | - | 用于自定义时间轴节点元素。TS 类型:`TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +dotColor | String | default | 时间轴颜色,内置 `primary/warning/error/default` 四种色值,可传入 16 进制颜色码或 RGB 颜色值.。可选项:primary/warning/error/default。TS 类型:`string` | N +label | TNode | - | 标签文本内容,可完全自定义。TS 类型:`string | TNode`。[通用类型定义](https://github.com/Tencent/tdesign-react/blob/develop/src/common.ts) | N +labelAlign | String | - | 标签信息相对于时间轴的位置,在 `mode='alternate'` 时生效,优先级高于 `Timeline.labelAlign`。可选项:left/right/top/bottom | N diff --git a/src/timeline/type.ts b/src/timeline/type.ts new file mode 100644 index 0000000000..3cbb188e9c --- /dev/null +++ b/src/timeline/type.ts @@ -0,0 +1,67 @@ +/* eslint-disable */ + +/** + * 该文件为脚本自动生成文件,请勿随意修改。如需修改请联系 PMC + * */ + +import { TNode, TElement } from '../common'; + +export interface TdTimelineProps { + /** + * 标签信息放在时间轴的位置,`mode='alternate'` 时生效。纵向时间轴信息位置:左侧、右侧或两侧,默认信息在时间轴右侧。横向时间轴信息位置:上方、下方、两侧 + * @default right + */ + labelAlign?: 'left' | 'right' | 'alternate' | 'top' | 'bottom'; + /** + * 时间轴方向:水平方向、垂直方向 + * @default vertical + */ + layout?: 'horizontal' | 'vertical'; + /** + * 标签与内容文本的位置关系,`alternate` 为展示在轴两侧,`same` 为展示在同一侧 + * @default alternate + */ + mode?: 'alternate' | 'same'; + /** + * 时间轴是否表现为倒序 + * @default false + */ + reverse?: boolean; + /** + * 步骤条风格 + * @default default + */ + theme?: 'default' | 'dot'; +} + +export interface TdTimelineItemProps { + /** + * 描述内容,同 content + */ + children?: TNode; + /** + * 描述内容 + */ + content?: TNode; + /** + * 用于自定义时间轴节点元素 + */ + dot?: TElement; + /** + * 时间轴颜色,内置 `primary/warning/error/default` 四种色值,可传入 16 进制颜色码或 RGB 颜色值. + * @default default + */ + dotColor?: string; + /** + * 标签文本内容,可完全自定义 + */ + label?: TNode; + /** + * 标签信息相对于时间轴的位置,在 `mode='alternate'` 时生效,优先级高于 `Timeline.labelAlign` + */ + labelAlign?: 'left' | 'right' | 'top' | 'bottom'; + /** + * 是否处在加载状态 + */ + loading?: boolean; +} diff --git a/src/timeline/useAlign.ts b/src/timeline/useAlign.ts new file mode 100644 index 0000000000..45fd9f6fa5 --- /dev/null +++ b/src/timeline/useAlign.ts @@ -0,0 +1,24 @@ +import { useMemo } from 'react'; +import log from '../_common/js/log'; + +const DefaultAlign = { + vertical: ['left', 'right'], + horizontal: ['top', 'bottom'], +}; + +export const useAlign = (align = 'left', layout = 'vertical') => + useMemo(() => { + let renderAlign = 'left'; + if (layout === 'vertical') { + const index = DefaultAlign.horizontal.indexOf(align); + const isError = index !== -1; + isError && log.warn('Timeline', 'If layout is vertical, align should be "left","alternate" or "right" '); + renderAlign = isError ? DefaultAlign.vertical[index] : align; + } else { + const index = DefaultAlign.vertical.indexOf(align); + const isError = index !== -1; + isError && log.warn('Timeline', 'If layout is horizontal, align should be "top","alternate" or "bottom" '); + renderAlign = isError ? DefaultAlign.horizontal[index] : align; + } + return renderAlign; + }, [align, layout]); diff --git a/test/ssr/__snapshots__/ssr.test.js.snap b/test/ssr/__snapshots__/ssr.test.js.snap index 9d531e73a6..c5b541a0e4 100644 --- a/test/ssr/__snapshots__/ssr.test.js.snap +++ b/test/ssr/__snapshots__/ssr.test.js.snap @@ -972,6 +972,20 @@ exports[`ssr snapshot test renders ./src/time-picker/_example/show-steps.jsx cor exports[`ssr snapshot test renders ./src/time-picker/_example/twelve-hour-meridian.jsx correctly 1`] = `"
    "`; +exports[`ssr snapshot test renders ./src/timeline/_example/base.tsx correctly 1`] = `"

    时间轴方向

    • 事件一
      2022-01-01
    • 事件二
      2022-02-01
    • 事件三
      2022-03-01
    • 事件四
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/customContent.tsx correctly 1`] = `"
    • 事件一
      事件一自定义内容
      2022-01-01
    • 事件二
      事件二自定义内容
      2022-02-01
    • 事件三
      事件三自定义内容
      2022-03-01
    • 事件四
      事件四自定义内容
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/customDot.tsx correctly 1`] = `"

    时间轴样式

    • 事件一
      2022-01-01
    • 事件二
      2022-02-01
    • 事件三
      2022-03-01
    • 事件四
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/layout.tsx correctly 1`] = `"

    时间轴方向

    对齐方式

    label对齐方式

    • 事件一
      2022-01-01
    • 事件二
      2022-02-01
    • 事件三
      2022-03-01
    • 事件四
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/loading.tsx correctly 1`] = `"

    加载中

    • 事件一
      2022-01-01
    • 事件二
      2022-02-01
    • 事件三
      2022-03-01
    • 事件四
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/reverse.tsx correctly 1`] = `"

    是否倒序

    • 事件一
      2022-01-01
    • 事件二
      2022-02-01
    • 事件三
      2022-03-01
    • 事件四
      2022-04-01
    "`; + +exports[`ssr snapshot test renders ./src/timeline/_example/theme.tsx correctly 1`] = `"
    • 已完成的时间
      2022-01-01
    • 成功的时间
      2022-02-01
    • 危险时间
      2022-03-01
    • 告警事件
      2022-04-01
    • 默认的时间
      2022-05-01
    • 自定义主题色
      2022-06-01
    "`; + exports[`ssr snapshot test renders ./src/tooltip/_example/arrow.jsx correctly 1`] = `""`; exports[`ssr snapshot test renders ./src/tooltip/_example/base.jsx correctly 1`] = `"
    "`;