mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
parent
6b55a32eef
commit
751bf40f60
@ -1,11 +1,10 @@
|
||||
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import type { TimelineItemProps } from './TimelineItem';
|
||||
import TimelineItemList from './TimelineItemList';
|
||||
import TimelineItem from './TimelineItem';
|
||||
import warning from '../_util/warning';
|
||||
import useItems from './useItems';
|
||||
|
||||
// CSSINJS
|
||||
import useStyle from './style';
|
||||
@ -20,6 +19,7 @@ export interface TimelineProps {
|
||||
style?: React.CSSProperties;
|
||||
reverse?: boolean;
|
||||
mode?: 'left' | 'alternate' | 'right';
|
||||
items?: TimelineItemProps[];
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
@ -29,83 +29,27 @@ type CompoundedComponent = React.FC<TimelineProps> & {
|
||||
|
||||
const Timeline: CompoundedComponent = (props) => {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
pending = null,
|
||||
pendingDot,
|
||||
children,
|
||||
className,
|
||||
rootClassName,
|
||||
reverse = false,
|
||||
mode = '' as TimelineProps['mode'],
|
||||
...restProps
|
||||
} = props;
|
||||
const { prefixCls: customizePrefixCls, children, items, ...restProps } = props;
|
||||
const prefixCls = getPrefixCls('timeline', customizePrefixCls);
|
||||
const pendingNode = typeof pending === 'boolean' ? null : pending;
|
||||
|
||||
// =================== Warning =====================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(!children, 'Timeline', '`Timeline.Item` is deprecated. Please use `items` instead.');
|
||||
}
|
||||
|
||||
// Style
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
|
||||
const pendingItem = pending ? (
|
||||
<TimelineItem pending={!!pending} dot={pendingDot || <LoadingOutlined />}>
|
||||
{pendingNode}
|
||||
</TimelineItem>
|
||||
) : null;
|
||||
|
||||
const timeLineItems = React.Children.toArray(children);
|
||||
timeLineItems.push(pendingItem!);
|
||||
if (reverse) {
|
||||
timeLineItems.reverse();
|
||||
}
|
||||
|
||||
const getPositionCls = (ele: React.ReactElement<any>, idx: number) => {
|
||||
if (mode === 'alternate') {
|
||||
if (ele.props.position === 'right') return `${prefixCls}-item-right`;
|
||||
if (ele.props.position === 'left') return `${prefixCls}-item-left`;
|
||||
return idx % 2 === 0 ? `${prefixCls}-item-left` : `${prefixCls}-item-right`;
|
||||
}
|
||||
if (mode === 'left') return `${prefixCls}-item-left`;
|
||||
if (mode === 'right') return `${prefixCls}-item-right`;
|
||||
if (ele.props.position === 'right') return `${prefixCls}-item-right`;
|
||||
return '';
|
||||
};
|
||||
|
||||
// Remove falsy items
|
||||
const truthyItems = timeLineItems.filter((item) => !!item);
|
||||
const itemsCount = React.Children.count(truthyItems);
|
||||
const lastCls = `${prefixCls}-item-last`;
|
||||
const items = React.Children.map(truthyItems, (ele: React.ReactElement<any>, idx) => {
|
||||
const pendingClass = idx === itemsCount - 2 ? lastCls : '';
|
||||
const readyClass = idx === itemsCount - 1 ? lastCls : '';
|
||||
return cloneElement(ele, {
|
||||
className: classNames([
|
||||
ele.props.className,
|
||||
!reverse && !!pending ? pendingClass : readyClass,
|
||||
getPositionCls(ele, idx),
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
const hasLabelItem = timeLineItems.some((item: React.ReactElement<any>) => !!item?.props?.label);
|
||||
|
||||
const classString = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-pending`]: !!pending,
|
||||
[`${prefixCls}-reverse`]: !!reverse,
|
||||
[`${prefixCls}-${mode}`]: !!mode && !hasLabelItem,
|
||||
[`${prefixCls}-label`]: hasLabelItem,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
rootClassName,
|
||||
hashId,
|
||||
);
|
||||
const mergedItems: TimelineItemProps[] = useItems(items, children);
|
||||
|
||||
return wrapSSR(
|
||||
<ul {...restProps} className={classString}>
|
||||
{items}
|
||||
</ul>,
|
||||
<TimelineItemList
|
||||
{...restProps}
|
||||
prefixCls={prefixCls}
|
||||
direction={direction}
|
||||
items={mergedItems}
|
||||
hashId={hashId}
|
||||
/>,
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -6,6 +6,7 @@ import type { LiteralUnion } from '../_util/type';
|
||||
type Color = 'blue' | 'red' | 'green' | 'gray';
|
||||
|
||||
export interface TimelineItemProps {
|
||||
key?: React.Key;
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
color?: LiteralUnion<Color>;
|
||||
|
92
components/timeline/TimelineItemList.tsx
Normal file
92
components/timeline/TimelineItemList.tsx
Normal file
@ -0,0 +1,92 @@
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
|
||||
import TimelineItem from './TimelineItem';
|
||||
import type { TimelineProps } from './Timeline';
|
||||
import type { TimelineItemProps } from './TimelineItem';
|
||||
|
||||
const TimelineItemList: React.FC<TimelineProps & { hashId: string; direction?: string }> = ({
|
||||
prefixCls,
|
||||
className,
|
||||
pending = false,
|
||||
children,
|
||||
items,
|
||||
rootClassName,
|
||||
reverse = false,
|
||||
direction,
|
||||
hashId,
|
||||
pendingDot,
|
||||
mode = '' as TimelineProps['mode'],
|
||||
...restProps
|
||||
}) => {
|
||||
const getPositionCls = (position: string, idx: number) => {
|
||||
if (mode === 'alternate') {
|
||||
if (position === 'right') return `${prefixCls}-item-right`;
|
||||
if (position === 'left') return `${prefixCls}-item-left`;
|
||||
return idx % 2 === 0 ? `${prefixCls}-item-left` : `${prefixCls}-item-right`;
|
||||
}
|
||||
if (mode === 'left') return `${prefixCls}-item-left`;
|
||||
if (mode === 'right') return `${prefixCls}-item-right`;
|
||||
if (position === 'right') return `${prefixCls}-item-right`;
|
||||
return '';
|
||||
};
|
||||
const mergedItems = [...(items || [])];
|
||||
const pendingNode = typeof pending === 'boolean' ? null : pending;
|
||||
|
||||
if (pending) {
|
||||
mergedItems.push({
|
||||
pending: !!pending,
|
||||
dot: pendingDot || <LoadingOutlined />,
|
||||
children: pendingNode,
|
||||
});
|
||||
}
|
||||
|
||||
if (reverse) {
|
||||
mergedItems.reverse();
|
||||
}
|
||||
const itemsCount = mergedItems.length;
|
||||
const lastCls = `${prefixCls}-item-last`;
|
||||
|
||||
const itemsList = mergedItems
|
||||
.filter((item: TimelineItemProps) => !!item)
|
||||
.map((item: TimelineItemProps, idx: number) => {
|
||||
const pendingClass = idx === itemsCount - 2 ? lastCls : '';
|
||||
const readyClass = idx === itemsCount - 1 ? lastCls : '';
|
||||
return (
|
||||
<TimelineItem
|
||||
className={classNames([
|
||||
className,
|
||||
!reverse && !!pending ? pendingClass : readyClass,
|
||||
getPositionCls(item?.position ?? '', idx),
|
||||
])}
|
||||
{...item}
|
||||
/* eslint-disable-next-line react/no-array-index-key */
|
||||
key={item?.key || idx}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const hasLabelItem = mergedItems.some((item: TimelineItemProps) => !!item?.label);
|
||||
|
||||
const classString = classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-pending`]: !!pending,
|
||||
[`${prefixCls}-reverse`]: !!reverse,
|
||||
[`${prefixCls}-${mode}`]: !!mode && !hasLabelItem,
|
||||
[`${prefixCls}-label`]: hasLabelItem,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
},
|
||||
className,
|
||||
rootClassName,
|
||||
hashId,
|
||||
);
|
||||
|
||||
return (
|
||||
<ul {...restProps} className={classString}>
|
||||
{itemsList}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimelineItemList;
|
@ -5,19 +5,22 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { render } from '../../../tests/utils';
|
||||
|
||||
const { Item } = TimeLine;
|
||||
|
||||
const renderFactory = (
|
||||
timeLineProps: TimelineProps = {},
|
||||
labelItems: TimelineProps['children'] = null,
|
||||
) =>
|
||||
const renderFactory = (timeLineProps: TimelineProps) =>
|
||||
render(
|
||||
<TimeLine {...timeLineProps}>
|
||||
<Item key="1">foo</Item>
|
||||
<Item key="2">bar</Item>
|
||||
<Item key="3">baz</Item>
|
||||
{labelItems}
|
||||
</TimeLine>,
|
||||
<TimeLine
|
||||
{...timeLineProps}
|
||||
items={[
|
||||
{
|
||||
children: 'foo',
|
||||
},
|
||||
{
|
||||
children: 'bar',
|
||||
},
|
||||
{
|
||||
children: 'baz',
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
describe('TimeLine', () => {
|
||||
@ -26,8 +29,60 @@ describe('TimeLine', () => {
|
||||
rtlTest(TimeLine);
|
||||
rtlTest(TimeLine.Item);
|
||||
|
||||
describe('render TimeLine.Item', () => {
|
||||
it('TimeLine.Item should correctly', () => {
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const { container } = render(
|
||||
<TimeLine reverse>
|
||||
<TimeLine.Item>foo</TimeLine.Item>
|
||||
<TimeLine.Item>bar</TimeLine.Item>
|
||||
<TimeLine.Item>baz</TimeLine.Item>
|
||||
</TimeLine>,
|
||||
);
|
||||
|
||||
// has 3 timeline item
|
||||
expect(container.querySelectorAll('li.ant-timeline-item')).toHaveLength(3);
|
||||
|
||||
// has only 1 timeline item is marked as the last item
|
||||
expect(container.querySelectorAll('li.ant-timeline-item-last')).toHaveLength(1);
|
||||
|
||||
// its last item is marked as the last item
|
||||
expect(container.querySelectorAll('li.ant-timeline-item')[2]).toHaveClass(
|
||||
'ant-timeline-item-last',
|
||||
);
|
||||
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Timeline] `Timeline.Item` is deprecated. Please use `items` instead.',
|
||||
);
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('has extra pending timeline item', () => {
|
||||
const { container } = render(
|
||||
<TimeLine pending={<div>pending...</div>} reverse mode="alternate">
|
||||
<TimeLine.Item>foo</TimeLine.Item>
|
||||
<TimeLine.Item position="right">bar</TimeLine.Item>
|
||||
<TimeLine.Item position="left">baz</TimeLine.Item>
|
||||
</TimeLine>,
|
||||
);
|
||||
expect(container.querySelectorAll('li.ant-timeline-item-pending')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("has no pending dot if without passing a truthy 'pending' prop", () => {
|
||||
const { queryByText } = render(
|
||||
<TimeLine pendingDot={<i>dot</i>} reverse>
|
||||
<TimeLine.Item>foo</TimeLine.Item>
|
||||
<TimeLine.Item>bar</TimeLine.Item>
|
||||
<TimeLine.Item position="right">baz</TimeLine.Item>
|
||||
</TimeLine>,
|
||||
);
|
||||
expect(queryByText('dot')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders items without passing any props correctly', () => {
|
||||
const { container } = renderFactory();
|
||||
const { container } = renderFactory({});
|
||||
|
||||
// has 3 timeline item
|
||||
expect(container.querySelectorAll('li.ant-timeline-item')).toHaveLength(3);
|
||||
@ -132,11 +187,21 @@ describe('TimeLine', () => {
|
||||
|
||||
it('renders Timeline item with label correctly', () => {
|
||||
const label = '2020-01-01';
|
||||
const { container } = renderFactory(
|
||||
{},
|
||||
<Item key="1" label={label}>
|
||||
foo
|
||||
</Item>,
|
||||
const { container } = render(
|
||||
<TimeLine
|
||||
items={[
|
||||
{
|
||||
label,
|
||||
children: 'foo',
|
||||
},
|
||||
{
|
||||
children: 'bar',
|
||||
},
|
||||
{
|
||||
children: 'baz',
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelectorAll('.ant-timeline-label')).toHaveLength(1);
|
||||
expect(container.querySelector('.ant-timeline-item-label')).toHaveTextContent(label);
|
||||
@ -148,9 +213,14 @@ describe('TimeLine', () => {
|
||||
presetColors.forEach((color) => {
|
||||
it(`className should have a preset color ${color}`, () => {
|
||||
const { container } = render(
|
||||
<TimeLine>
|
||||
<Item color={color}>foo</Item>
|
||||
</TimeLine>,
|
||||
<TimeLine
|
||||
items={[
|
||||
{
|
||||
color,
|
||||
children: 'foo',
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelector('.ant-timeline-item-head')).toHaveClass(
|
||||
`ant-timeline-item-head-${color}`,
|
||||
@ -167,9 +237,14 @@ describe('TimeLine', () => {
|
||||
nonPresetColors.forEach((color) => {
|
||||
it(`className should not have a non-preset color ${color}`, () => {
|
||||
const { container } = render(
|
||||
<TimeLine>
|
||||
<Item color={color}>foo</Item>
|
||||
</TimeLine>,
|
||||
<TimeLine
|
||||
items={[
|
||||
{
|
||||
color,
|
||||
children: 'foo',
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(container.querySelector('.ant-timeline-item-head')).not.toHaveClass(
|
||||
`ant-timeline-item-head-${color}`,
|
||||
|
@ -3,20 +3,33 @@ import { ClockCircleOutlined } from '@ant-design/icons';
|
||||
import { Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Timeline mode="alternate">
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item color="green">Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item dot={<ClockCircleOutlined style={{ fontSize: '16px' }} />}>
|
||||
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
|
||||
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto
|
||||
beatae vitae dicta sunt explicabo.
|
||||
</Timeline.Item>
|
||||
<Timeline.Item color="red">Network problems being solved 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item dot={<ClockCircleOutlined style={{ fontSize: '16px' }} />}>
|
||||
Technical testing 2015-09-01
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
mode="alternate"
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
color: 'green',
|
||||
},
|
||||
{
|
||||
dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />,
|
||||
children: `Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.`,
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
children: 'Network problems being solved 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />,
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -2,12 +2,22 @@ import React from 'react';
|
||||
import { Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Timeline>
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Technical testing 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Network problems being solved 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Network problems being solved 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -3,33 +3,62 @@ import { SmileOutlined } from '@ant-design/icons';
|
||||
import { Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Timeline>
|
||||
<Timeline.Item color="green">Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item color="green">Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item color="red">
|
||||
<p>Solve initial network problems 1</p>
|
||||
<p>Solve initial network problems 2</p>
|
||||
<p>Solve initial network problems 3 2015-09-01</p>
|
||||
</Timeline.Item>
|
||||
<Timeline.Item>
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</Timeline.Item>
|
||||
<Timeline.Item color="gray">
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</Timeline.Item>
|
||||
<Timeline.Item color="gray">
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</Timeline.Item>
|
||||
<Timeline.Item color="#00CCFF" dot={<SmileOutlined />}>
|
||||
<p>Custom color testing</p>
|
||||
</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
items={[
|
||||
{
|
||||
color: 'green',
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
color: 'green',
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
color: 'red',
|
||||
children: (
|
||||
<>
|
||||
<p>Solve initial network problems 1</p>
|
||||
<p>Solve initial network problems 2</p>
|
||||
<p>Solve initial network problems 3 2015-09-01</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
children: (
|
||||
<>
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
children: (
|
||||
<>
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
children: (
|
||||
<>
|
||||
<p>Technical testing 1</p>
|
||||
<p>Technical testing 2</p>
|
||||
<p>Technical testing 3 2015-09-01</p>
|
||||
</>
|
||||
),
|
||||
},
|
||||
{
|
||||
color: '#00CCFF',
|
||||
dot: <SmileOutlined />,
|
||||
children: <p>Custom color testing</p>,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -3,14 +3,24 @@ import { ClockCircleOutlined } from '@ant-design/icons';
|
||||
import { Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Timeline>
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item dot={<ClockCircleOutlined className="timeline-clock-icon" />} color="red">
|
||||
Technical testing 2015-09-01
|
||||
</Timeline.Item>
|
||||
<Timeline.Item>Network problems being solved 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
},
|
||||
{
|
||||
dot: <ClockCircleOutlined className="timeline-clock-icon" />,
|
||||
color: 'red',
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Network problems being solved 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -22,12 +22,26 @@ const App: React.FC = () => {
|
||||
<Radio value="right">Right</Radio>
|
||||
<Radio value="alternate">Alternate</Radio>
|
||||
</Radio.Group>
|
||||
<Timeline mode={mode}>
|
||||
<Timeline.Item label="2015-09-01">Create a services</Timeline.Item>
|
||||
<Timeline.Item label="2015-09-01 09:12:11">Solve initial network problems</Timeline.Item>
|
||||
<Timeline.Item>Technical testing</Timeline.Item>
|
||||
<Timeline.Item label="2015-09-01 09:12:11">Network problems being solved</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
mode={mode}
|
||||
items={[
|
||||
{
|
||||
label: '2015-09-01',
|
||||
children: 'Create a services',
|
||||
},
|
||||
{
|
||||
label: '2015-09-01 09:12:11',
|
||||
children: 'Solve initial network problems',
|
||||
},
|
||||
{
|
||||
children: 'Technical testing',
|
||||
},
|
||||
{
|
||||
label: '2015-09-01 09:12:11',
|
||||
children: 'Network problems being solved',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -10,11 +10,21 @@ const App: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Timeline pending="Recording..." reverse={reverse}>
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Technical testing 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
pending="Recording..."
|
||||
reverse={reverse}
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Button type="primary" style={{ marginTop: 16 }} onClick={handleClick}>
|
||||
Toggle Reverse
|
||||
</Button>
|
||||
|
@ -3,14 +3,25 @@ import { ClockCircleOutlined } from '@ant-design/icons';
|
||||
import { Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<Timeline mode="right">
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item dot={<ClockCircleOutlined style={{ fontSize: '16px' }} />} color="red">
|
||||
Technical testing 2015-09-01
|
||||
</Timeline.Item>
|
||||
<Timeline.Item>Network problems being solved 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
mode="right"
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
},
|
||||
{
|
||||
dot: <ClockCircleOutlined style={{ fontSize: '16px' }} />,
|
||||
color: 'red',
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Network problems being solved 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -3,12 +3,22 @@ import { ConfigProvider, Timeline } from 'antd';
|
||||
|
||||
const App: React.FC = () => (
|
||||
<ConfigProvider theme={{ token: { wireframe: true } }}>
|
||||
<Timeline>
|
||||
<Timeline.Item>Create a services site 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Solve initial network problems 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Technical testing 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>Network problems being solved 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
<Timeline
|
||||
items={[
|
||||
{
|
||||
children: 'Create a services site 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Solve initial network problems 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Technical testing 2015-09-01',
|
||||
},
|
||||
{
|
||||
children: 'Network problems being solved 2015-09-01',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
);
|
||||
|
||||
|
@ -26,29 +26,37 @@ Vertical display timeline.
|
||||
<code src="./demo/label.tsx">Label</code>
|
||||
<code src="./demo/wireframe.tsx" debug>Wireframe</code>
|
||||
|
||||
## API
|
||||
```__react
|
||||
import Alert from '../alert';
|
||||
ReactDOM.render(<Alert message="After version 5.3.0, we provide a simpler usage <Timeline items={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 6.0." />, mountNode);
|
||||
```
|
||||
|
||||
```jsx
|
||||
<Timeline>
|
||||
<Timeline.Item>step1 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>step2 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>step3 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>step4 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
// works when >=5.3.0, recommended ✅
|
||||
const items = [{ children: 'sample', label: 'sample' }];
|
||||
return <Timeline items={items} />;
|
||||
|
||||
// works when <5.3.0, deprecated when >=5.3.0 🙅🏻♀️
|
||||
<Timeline onChange={onChange}>
|
||||
<Timeline.Item>Sample</Timeline.Item>
|
||||
</Timeline>;
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Timeline
|
||||
|
||||
Timeline
|
||||
|
||||
| Property | Description | Type | Default |
|
||||
| --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| mode | By sending `alternate` the timeline will distribute the nodes to the left and right | `left` \| `alternate` \| `right` | - |
|
||||
| pending | Set the last ghost node's existence or its content | boolean \| ReactNode | false |
|
||||
| pendingDot | Set the dot of the last ghost node when pending is true | ReactNode | <LoadingOutlined /> |
|
||||
| reverse | Whether reverse nodes or not | boolean | false |
|
||||
| items | 选项配置 | [Items](#Items) | [] | 5.3.0 |
|
||||
|
||||
### Timeline.Item
|
||||
### Items
|
||||
|
||||
Node of timeline
|
||||
|
||||
@ -57,4 +65,5 @@ Node of timeline
|
||||
| color | Set the circle's color to `blue`, `red`, `green`, `gray` or other custom colors | string | `blue` |
|
||||
| dot | Customize timeline dot | ReactNode | - |
|
||||
| label | Set the label | ReactNode | - |
|
||||
| children | Set the content | ReactNode | - |
|
||||
| position | Customize node position | `left` \| `right` | - |
|
||||
|
@ -27,29 +27,37 @@ demo:
|
||||
<code src="./demo/label.tsx">标签</code>
|
||||
<code src="./demo/wireframe.tsx" debug>线框风格</code>
|
||||
|
||||
## API
|
||||
```__react
|
||||
import Alert from '../alert';
|
||||
ReactDOM.render(<Alert message="After version 5.3.0, we provide a simpler usage <Timeline items={[...]} /> with better performance and potential of writing simpler code style in your applications. Meanwhile, we deprecated the old usage in browser console, we will remove it in antd 6.0." />, mountNode);
|
||||
```
|
||||
|
||||
```jsx
|
||||
<Timeline>
|
||||
<Timeline.Item>创建服务现场 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>初步排除网络异常 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>技术测试异常 2015-09-01</Timeline.Item>
|
||||
<Timeline.Item>网络异常正在修复 2015-09-01</Timeline.Item>
|
||||
</Timeline>
|
||||
// >=5.3.0 可用,推荐的写法 ✅
|
||||
const items = [{ children: 'sample', label: 'sample' }];
|
||||
return <Timeline items={items} />;
|
||||
|
||||
// <5.3.0 可用,>=5.3.0 时不推荐 🙅🏻♀️
|
||||
<Timeline onChange={onChange}>
|
||||
<Timeline.Item>Sample</Timeline.Item>
|
||||
</Timeline>;
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Timeline
|
||||
|
||||
时间轴。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| mode | 通过设置 `mode` 可以改变时间轴和内容的相对位置 | `left` \| `alternate` \| `right` | - |
|
||||
| pending | 指定最后一个幽灵节点是否存在或内容 | boolean \| ReactNode | false |
|
||||
| pendingDot | 当最后一个幽灵节点存在時,指定其时间图点 | ReactNode | <LoadingOutlined /> |
|
||||
| reverse | 节点排序 | boolean | false |
|
||||
| items | 选项配置 | [Items](#Items) | [] | 5.3.0 |
|
||||
|
||||
### Timeline.Item
|
||||
### Items
|
||||
|
||||
时间轴的每一个节点。
|
||||
|
||||
@ -58,4 +66,5 @@ demo:
|
||||
| color | 指定圆圈颜色 `blue`、`red`、`green`、`gray`,或自定义的色值 | string | `blue` |
|
||||
| dot | 自定义时间轴点 | ReactNode | - |
|
||||
| label | 设置标签 | ReactNode | - |
|
||||
| children | 设置内容 | ReactNode | - |
|
||||
| position | 自定义节点位置 | `left` \| `right` | - |
|
||||
|
14
components/timeline/useItems.tsx
Normal file
14
components/timeline/useItems.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import type * as React from 'react';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import type { TimelineItemProps } from './TimelineItem';
|
||||
|
||||
function useItems(items?: TimelineItemProps[], children?: React.ReactNode): TimelineItemProps[] {
|
||||
if (items && Array.isArray(items)) return items;
|
||||
|
||||
return toArray(children).map((ele: React.ReactElement<any>) => ({
|
||||
children: ele?.props?.children ?? '',
|
||||
...ele.props,
|
||||
}));
|
||||
}
|
||||
|
||||
export default useItems;
|
Loading…
Reference in New Issue
Block a user