Feature list component (#7150)

* add list component

* fixed the demo syntax

* update list snapshots
This commit is contained in:
niko 2017-08-09 15:45:08 +08:00 committed by ddcat1115
parent 2b1bed42c9
commit 12bbe3776c
13 changed files with 1824 additions and 0 deletions

View File

@ -25,6 +25,7 @@ Array [
"Input",
"InputNumber",
"Layout",
"List",
"LocaleProvider",
"message",
"Menu",

View File

@ -57,6 +57,8 @@ export { default as InputNumber } from './input-number';
export { default as Layout } from './layout';
export { default as List } from './list';
export { default as LocaleProvider } from './locale-provider';
export { default as message } from './message';

122
components/list/Item.tsx Normal file
View File

@ -0,0 +1,122 @@
import React from 'react';
import classNames from 'classnames';
import Icon from '../icon';
export interface ListItemProps {
className?: string;
children?: React.ReactNode;
prefixCls?: string;
style?: React.CSSProperties;
extra: React.ReactNode;
Meta: React.ReactNode;
Content: React.ReactNode;
Action: React.ReactNode;
}
export interface ListItemMetaProps {
avatar?: React.ReactNode;
className?: string;
children?: React.ReactNode;
description: React.ReactNode;
prefixCls?: string;
style?: React.CSSProperties;
title: React.ReactNode;
}
export interface ListItemContentProps {
className?: string;
children?: React.ReactNode;
prefixCls?: string;
style?: React.CSSProperties;
}
export interface ListItemActionProps {
actions: any[];
className?: string;
children?: React.ReactNode;
prefixCls?: string;
style?: React.CSSProperties;
}
export const Meta = (props: ListItemMetaProps) => {
const {
prefixCls = 'ant-list',
className,
avatar,
title,
description,
...others,
} = props;
const classString = classNames(`${prefixCls}-item-meta`, className);
const content = (
<div className={`${prefixCls}-item-meta-content`}>
{title && <h4 className={`${prefixCls}-item-meta-title`}>{title}</h4>}
{description && <p className={`${prefixCls}-item-meta-description`}>{description}</p>}
</div>
);
return (
<div {...others} className={classString}>
{avatar && <div className={`${prefixCls}-item-meta-avatar`}>{avatar}</div>}
{(title || description) && content}
</div>
);
};
export const Content = (props: ListItemContentProps) => {
const { prefixCls = 'ant-list', children, className, ...others } = props;
const classString = classNames(`${prefixCls}-item-content`, className);
return (
<div {...others} className={classString}>
{children}
</div>
);
};
export const Action = (props: ListItemActionProps) => {
const { prefixCls = 'ant-list', children, actions, className, ...others } = props;
const classString = classNames(`${prefixCls}-item-action`, className);
const actionsContent = actions && actions.map((action, i) => (
<span
key={`antd-list-item-action-${action.text}-${i}`}
className={`${prefixCls}-item-action-item`}
onClick={action.onClick || (() => {})}
>
{action.icon && <Icon type={action.icon}/>}
{action.text}
{i !== (actions.length - 1) && <em className={`${prefixCls}-item-action-item-split`}/>}
</span>
));
return (
<div {...others} className={classString}>
{actions ? actionsContent : children}
</div>
);
};
export default class Item extends React.Component<ListItemProps, any> {
static Meta: typeof Meta = Meta;
static Content: typeof Content = Content;
static Action: typeof Action = Action;
render() {
const { prefixCls = 'ant-list', children, extra, className, ...others } = this.props;
const classString = classNames(`${prefixCls}-item`, className);
const extraContent = <div className={`${prefixCls}-item-extra-wrap`}>
<div className={`${prefixCls}-item-main`}>{children}</div>
<div className={`${prefixCls}-item-extra`}>{extra}</div>
</div>;
return (
<div {...others} className={classString}>
{extra ? extraContent : children}
</div>
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('list');

View File

@ -0,0 +1,79 @@
---
order: 0
title:
zh-CN: 基础列表
en-US: Basic
---
## zh-CN
基础列表。
## en-US
Basic List.
````jsx
import { List, Avatar } from 'antd';
ReactDOM.render(
<List
itemLayout="horizontal"
showLoadMore
onLoadMore={() => {}}
>
<List.Item>
<List.Item.Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={<a href="https://ant.design">Ant design</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
<List.Item.Content>
Content
</List.Item.Content>
<List.Item.Action>
<a>edit</a> | <a>more</a>
</List.Item.Action>
</List.Item>
<List.Item>
<List.Item.Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={<a href="https://ant.design">Ant design</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
<List.Item.Content>
Content
</List.Item.Content>
<List.Item.Action>
<a>edit</a> | <a>more</a>
</List.Item.Action>
</List.Item>
<List.Item>
<List.Item.Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={<a href="https://ant.design">Ant design</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
<List.Item.Content>
Content
</List.Item.Content>
<List.Item.Action>
<a>edit</a> | <a>more</a>
</List.Item.Action>
</List.Item>
<List.Item>
<List.Item.Meta
avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
title={<a href="https://ant.design">Ant design</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
<List.Item.Content>
Content
</List.Item.Content>
<List.Item.Action>
<a>edit</a> | <a>more</a>
</List.Item.Action>
</List.Item>
</List>
, mountNode);
````

View File

@ -0,0 +1,74 @@
---
order: 1
title:
zh-CN: 竖排列表样式
en-US: Layout Vertical
---
## zh-CN
基础列表。
## en-US
Basic List.
````jsx
import { List, Avatar } from 'antd';
const listData = [];
for (let i = 0; i < 10; i++) {
listData.push({
href: 'http://ant.design',
title: `ant design part ${i}`,
avatar: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png',
description: 'Ant Design, a design language for background applications, is refined by Ant UED Team.',
content: 'We supply a series of design principles, practical patterns and high quality design resources (Sketch and Axure), to help people create their product prototypes beautifully and efficiently.',
});
}
const pagination = {
pageSize: 10,
current: 1,
total: listData.length,
onChange: (() => {}),
};
ReactDOM.render(
<List itemLayout="vertical" pagination={pagination}>
{
listData.map(item => (
<List.Item
key={item.title}
extra={<img width={272} alt="logo" src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png" />}
>
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href={item.href}>{item.title}</a>}
description={item.description}
/>
<List.Item.Content>
{item.content}
</List.Item.Content>
<List.Item.Action
actions={[
{
icon: 'star-o',
text: 156,
},
{
icon: 'like-o',
text: 156,
},
{
icon: 'message',
text: 2,
},
]}
/>
</List.Item>
))
}
</List>
, mountNode);
````

View File

@ -0,0 +1,45 @@
---
category: Components
type: Data Display
title: List
cols: 1
---
Simple List.
## When To Use
A list can be used to display content related to a single subject. The content can consist of multiple elements of varying type and size.
## API
### List
| Property | Description | Type | Default |
|----------|----------------|----------|--------------|
| bordered | - | string \| boolean | false |
| loading | -| boolean | false |
| itemLayout | - | string | - |
| showLoadMore | -| boolean | false |
| loadingMore | - | boolean | false |
| onMoreClick | -| function | - |
| pagination | - | boolean \| object | false |
### List.Item
| Property | Description | Type | Default |
---------|-------------|------|---------
| extra | - | string\|ReactNode | - |
### List.Item.Meta
| Property | Description | Type | Default |
---------|-------------|------|---------
| avatar | - | ReactNode | - |
| title | - | string\|ReactNode | - |
| description | - | string\|ReactNode | - |
### List.Item.Action
| Property | Description | Type | Default |
---------|-------------|------|---------
| actions | - | Array | - |

85
components/list/index.tsx Normal file
View File

@ -0,0 +1,85 @@
import React, { Component } from 'react';
import classNames from 'classnames';
import Spin from '../spin';
import Icon from '../icon';
import Pagination from '../pagination';
import Button from '../button';
import Item from './Item';
export interface ListProps {
bordered?: boolean;
className?: string;
children?: React.ReactNode;
extra?: React.ReactNode;
id?: string;
itemLayout: string;
loading?: boolean;
showLoadMore?: boolean;
loadingMore?: boolean;
onLoadMore?: React.FormEventHandler<any>;
pagination?: any;
prefixCls?: string;
style?: React.CSSProperties;
}
export default class List extends Component<ListProps> {
static Item: typeof Item = Item;
render() {
const {
bordered = true,
className,
children,
loading = false,
itemLayout,
showLoadMore = false,
loadingMore = false,
onLoadMore = (() => {
}),
pagination = false,
prefixCls = 'ant-list',
} = this.props;
const classString = classNames(prefixCls, className, {
[`${prefixCls}-vertical`]: itemLayout === 'vertical',
[`${prefixCls}-bordered`]: bordered,
[`${prefixCls}-loading`]: loading,
});
const moreButton = (
<Button onClick={onLoadMore}>
<Icon type="loading"/>
...
</Button>
);
const moreContent = (
<div className={`${prefixCls}-more`}>
{loadingMore ? moreButton : <Button onClick={onLoadMore}>...</Button>}
</div>
);
const paginationContent = (
<div className={`${prefixCls}-pagination`}>
<Pagination {...pagination} />
</div>
);
const loadingContent = (
<div className={`${prefixCls}-spin`}>
<Spin />
</div>
);
return (
<div className={classString}>
{loading && loadingContent}
{!loading && children}
{showLoadMore && moreContent}
{(!showLoadMore && pagination) && paginationContent}
</div>
);
}
}

View File

@ -0,0 +1,54 @@
---
category: Components
type: Data Display
title: List
subtitle: 列表
cols: 1
---
通用列表。
## 何时使用
最基础的列表展示,可承载文字、列表、图片、段落,常用于后台数据展示页面。
## API
### List
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|--------------|
| bordered | 是否展示边框 | boolean | false |
| loading | 当卡片内容还在加载中时,可以用 loading 展示一个占位 | boolean | false |
| itemLayout | 设置 List.Item 布局, 设置成 vertical 则竖直样式显示, 默认横排 | string | - |
| showLoadMore | 是否显示加载更多按钮 | boolean | false |
| loadingMore | 是否显示加载更多按钮的 loading 状态 | boolean | false |
| onMoreClick | 点击 more 按钮的回调 | function | - |
| pagination | 对应的 pagination 配置, 设置 false 不显示 | boolean \| object | false |
### List.Item
| 参数 | 说明 | 类型 | 默认值 |
---------|-------------|------|---------
| extra | 额外内容, 通常用在 itemLayout 为 vertical 的情况下, 展示右侧内容; horizontal 展示在列表元素最右侧 | string\|ReactNode | - |
### List.Item.Meta
| 参数 | 说明 | 类型 | 默认值 |
---------|-------------|------|---------
| avatar | 列表元素的图标 | ReactNode | - |
| title | 列表元素的标题 | string\|ReactNode | - |
| description | 列表元素的描述内容 | string\|ReactNode | - |
### List.Item.Action
| 参数 | 说明 | 类型 | 默认值 |
---------|-------------|------|---------
| actions | 如果此参数存在, 那么会将其中的数据转换成符合标准 ant design 设计的 action 样式元素 | Array | - |
### List.Item.Action actions props
| 参数 | 说明 | 类型 | 默认值 |
|----------|----------------|----------|-----------------|
| icon | icon 图标 | string| - |
| text | 文案 | string | - |
| onClick | 点击回掉 | function | - |

View File

@ -0,0 +1,146 @@
@import "../../style/themes/default";
@import "../../style/mixins/index";
@list-prefix-cls: ~"@{ant-prefix}-list";
.@{list-prefix-cls} {
&-more, &-pagination {
margin-top: 24px;
text-align: center;
}
&-more {
button {
padding-left: 32px;
padding-right: 32px;
}
}
&-spin {
text-align: center;
min-height: 48px;
}
&-item {
align-items: center;
display: flex;
padding-top: 24px;
padding-bottom: 24px;
&:hover {
.@{list-prefix-cls}-item-meta-title {
color: @primary-color;
a {
color: @primary-color;
}
}
}
&-meta {
align-items: center;
display: flex;
font-size: 0;
&-avatar {
flex: 0;
margin-right: 16px;
}
&-content {
flex: 1 0;
}
&-title {
color: @text-color;
margin-bottom: 4px;
font-size: @font-size-base;
line-height: 22px;
a {
color: @text-color;
}
}
&-description {
color: @text-color-secondary;
font-size: @font-size-base;
line-height: 22px;
}
}
&-content {
display: flex;
flex: 1;
justify-content: flex-end;
}
&-action {
flex: 0 1 auto;
margin-left: 48px;
&-item {
color: @text-color-secondary;
cursor: pointer;
padding: 0 16px;
position: relative;
font-size: @font-size-base;
line-height: 22px;
i {
margin-right: 8px;
}
&-split {
background-color: @border-color-split;
margin-top: -7px;
position: absolute;
top: 50%;
right: 0;
width: 1px;
height: 14px;
}
}
&-item:first-child {
padding-left: 0;
}
}
&-main {
display: flex;
flex: 1;
}
&-extra {
flex: 0;
}
}
}
.@{list-prefix-cls}-bordered {
.@{list-prefix-cls}-item {
border-bottom: 1px solid @border-color-base;
padding-bottom: 23px;
}
}
.@{list-prefix-cls}-vertical {
.@{list-prefix-cls}-item {
display: block;
padding-bottom: 8px;
&-extra-wrap {
display: flex;
}
&-main {
display: block;
flex: 1;
}
&-extra {
margin-left: 58px;
flex: 0;
}
&-meta {
margin-bottom: 16px;
&-avatar {
display: none;
}
&-title {
color: @heading-color;
margin-bottom: 12px;
font-size: @font-size-lg;
line-height: 24px;
}
}
&-content {
display: block;
color: @text-color;
font-size: @font-size-base;
margin-bottom: 16px;
}
&-action {
margin-left: auto;
}
}
}

View File

@ -0,0 +1,8 @@
import '../../style/index.less';
import './index.less';
// style dependencies
import '../../spin/style';
import '../../icon/style';
import '../../pagination/style';
import '../../button/style';

View File

@ -25,6 +25,7 @@ Array [
"Input",
"InputNumber",
"Layout",
"List",
"LocaleProvider",
"message",
"Menu",