mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-11-29 18:50:00 +08:00
fix: Lots of Descriptions (#21542)
* refactor * class name * update demo snapshot * clean up * update snapshot * fix test case * more test case * adjust logic
This commit is contained in:
parent
8d7f1dadef
commit
1fad2b0277
67
components/descriptions/Cell.tsx
Normal file
67
components/descriptions/Cell.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
export interface CellProps {
|
||||
itemPrefixCls: string;
|
||||
span: number;
|
||||
className?: string;
|
||||
component: string;
|
||||
style?: React.CSSProperties;
|
||||
bordered?: boolean;
|
||||
label?: React.ReactNode;
|
||||
content?: React.ReactNode;
|
||||
colon?: boolean;
|
||||
}
|
||||
|
||||
const Cell: React.FC<CellProps> = ({
|
||||
itemPrefixCls,
|
||||
component,
|
||||
span,
|
||||
className,
|
||||
style,
|
||||
bordered,
|
||||
label,
|
||||
content,
|
||||
colon,
|
||||
}) => {
|
||||
const Component = component as any;
|
||||
|
||||
if (bordered) {
|
||||
return (
|
||||
<Component
|
||||
className={classNames(
|
||||
{
|
||||
[`${itemPrefixCls}-item-label`]: label,
|
||||
[`${itemPrefixCls}-item-content`]: content,
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
colSpan={span}
|
||||
>
|
||||
{label || content}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Component
|
||||
className={classNames(`${itemPrefixCls}-item`, className)}
|
||||
style={style}
|
||||
colSpan={span}
|
||||
>
|
||||
{label && (
|
||||
<span
|
||||
className={classNames(`${itemPrefixCls}-item-label`, {
|
||||
[`${itemPrefixCls}-item-colon`]: !bordered && colon,
|
||||
})}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{content && <span className={classNames(`${itemPrefixCls}-item-content`)}>{content}</span>}
|
||||
</Component>
|
||||
);
|
||||
};
|
||||
|
||||
export default Cell;
|
@ -1,72 +0,0 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { DescriptionsItemProps } from './index';
|
||||
|
||||
interface ColProps {
|
||||
child: React.ReactElement<DescriptionsItemProps>;
|
||||
bordered: boolean;
|
||||
colon: boolean;
|
||||
type?: 'label' | 'content';
|
||||
layout?: 'horizontal' | 'vertical';
|
||||
}
|
||||
|
||||
const Col: React.SFC<ColProps> = props => {
|
||||
const { child, bordered, colon, type, layout } = props;
|
||||
const { prefixCls, label, className, children, span = 1 } = child.props;
|
||||
const labelProps: any = {
|
||||
className: classNames(`${prefixCls}-item-label`, {
|
||||
[`${prefixCls}-item-colon`]: colon,
|
||||
[`${prefixCls}-item-no-label`]: !label,
|
||||
}),
|
||||
key: 'label',
|
||||
};
|
||||
if (layout === 'vertical') {
|
||||
labelProps.colSpan = span * 2 - 1;
|
||||
}
|
||||
|
||||
if (bordered) {
|
||||
if (type === 'label') {
|
||||
return <th {...labelProps}>{label}</th>;
|
||||
}
|
||||
return (
|
||||
<td
|
||||
className={classNames(`${prefixCls}-item-content`, className)}
|
||||
key="content"
|
||||
colSpan={span * 2 - 1}
|
||||
>
|
||||
{children}
|
||||
</td>
|
||||
);
|
||||
}
|
||||
if (layout === 'vertical') {
|
||||
if (type === 'content') {
|
||||
return (
|
||||
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
|
||||
<span className={`${prefixCls}-item-content`} key="content">
|
||||
{children}
|
||||
</span>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
|
||||
<span
|
||||
className={classNames(`${prefixCls}-item-label`, { [`${prefixCls}-item-colon`]: colon })}
|
||||
key="label"
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
</td>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<td colSpan={span} className={classNames(`${prefixCls}-item`, className)}>
|
||||
<span {...labelProps}>{label}</span>
|
||||
<span className={`${prefixCls}-item-content`} key="content">
|
||||
{children}
|
||||
</span>
|
||||
</td>
|
||||
);
|
||||
};
|
||||
|
||||
export default Col;
|
15
components/descriptions/Item.tsx
Normal file
15
components/descriptions/Item.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import * as React from 'react';
|
||||
|
||||
export interface DescriptionsItemProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
label?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
span?: number;
|
||||
}
|
||||
|
||||
const DescriptionsItem: React.SFC<DescriptionsItemProps> = ({ children }) =>
|
||||
children as JSX.Element;
|
||||
|
||||
export default DescriptionsItem;
|
118
components/descriptions/Row.tsx
Normal file
118
components/descriptions/Row.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import * as React from 'react';
|
||||
import { DescriptionsItemProps } from './Item';
|
||||
import Cell from './Cell';
|
||||
|
||||
interface CellConfig {
|
||||
component: string | [string, string];
|
||||
type: string;
|
||||
showLabel?: boolean;
|
||||
showContent?: boolean;
|
||||
}
|
||||
|
||||
function renderCells(
|
||||
items: React.ReactElement<DescriptionsItemProps>[],
|
||||
{ colon, prefixCls, bordered }: RowProps,
|
||||
{ component, type, showLabel, showContent }: CellConfig,
|
||||
) {
|
||||
return items.map(
|
||||
(
|
||||
{
|
||||
props: {
|
||||
label,
|
||||
children,
|
||||
prefixCls: itemPrefixCls = prefixCls,
|
||||
className,
|
||||
style,
|
||||
span = 1,
|
||||
},
|
||||
key,
|
||||
},
|
||||
index,
|
||||
) => {
|
||||
if (typeof component === 'string') {
|
||||
return (
|
||||
<Cell
|
||||
key={`${type}-${key || index}`}
|
||||
className={className}
|
||||
style={style}
|
||||
span={span}
|
||||
colon={colon}
|
||||
component={component}
|
||||
itemPrefixCls={itemPrefixCls}
|
||||
bordered={bordered}
|
||||
label={showLabel ? label : null}
|
||||
content={showContent ? children : null}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Cell
|
||||
key={`label-${key || index}`}
|
||||
className={className}
|
||||
style={style}
|
||||
span={1}
|
||||
colon={colon}
|
||||
component={component[0]}
|
||||
itemPrefixCls={itemPrefixCls}
|
||||
bordered={bordered}
|
||||
label={label}
|
||||
/>
|
||||
<Cell
|
||||
key={`content-${key || index}`}
|
||||
className={className}
|
||||
style={style}
|
||||
span={span * 2 - 1}
|
||||
component={component[1]}
|
||||
itemPrefixCls={itemPrefixCls}
|
||||
bordered={bordered}
|
||||
content={children}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export interface RowProps {
|
||||
prefixCls: string;
|
||||
vertical: boolean;
|
||||
children: React.ReactElement<DescriptionsItemProps>[];
|
||||
bordered?: boolean;
|
||||
colon: boolean;
|
||||
index: number;
|
||||
}
|
||||
|
||||
const Row: React.FC<RowProps> = props => {
|
||||
const { prefixCls, vertical, children, index, bordered } = props;
|
||||
if (vertical) {
|
||||
return (
|
||||
<>
|
||||
<tr key={`label-${index}`} className={`${prefixCls}-row`}>
|
||||
{renderCells(children, props, { component: 'th', type: 'label', showLabel: true })}
|
||||
</tr>
|
||||
<tr key={`content-${index}`} className={`${prefixCls}-row`}>
|
||||
{renderCells(children, props, {
|
||||
component: 'td',
|
||||
type: 'content',
|
||||
showContent: true,
|
||||
})}
|
||||
</tr>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<tr key={index} className={`${prefixCls}-row`}>
|
||||
{renderCells(children, props, {
|
||||
component: bordered ? ['th', 'td'] : 'td',
|
||||
type: 'item',
|
||||
showLabel: true,
|
||||
showContent: true,
|
||||
})}
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
export default Row;
|
@ -121,7 +121,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Product
|
||||
</th>
|
||||
@ -132,7 +133,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
Cloud Database
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Billing Mode
|
||||
</th>
|
||||
@ -143,7 +145,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
Prepaid
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Automatic Renewal
|
||||
</th>
|
||||
@ -158,7 +161,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Order time
|
||||
</th>
|
||||
@ -169,7 +173,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
2018-04-24 18:00:00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Usage Time
|
||||
</th>
|
||||
@ -184,7 +189,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Status
|
||||
</th>
|
||||
@ -210,7 +216,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Negotiated Amount
|
||||
</th>
|
||||
@ -221,7 +228,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
$80.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Discount
|
||||
</th>
|
||||
@ -232,7 +240,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
$20.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Official Receipts
|
||||
</th>
|
||||
@ -247,7 +256,8 @@ exports[`renders ./components/descriptions/demo/border.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Config Info
|
||||
</th>
|
||||
@ -294,7 +304,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Product
|
||||
</th>
|
||||
@ -305,7 +316,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
Cloud Database
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Billing
|
||||
</th>
|
||||
@ -316,7 +328,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
Prepaid
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
time
|
||||
</th>
|
||||
@ -331,7 +344,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Amount
|
||||
</th>
|
||||
@ -342,7 +356,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
$80.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Discount
|
||||
</th>
|
||||
@ -353,7 +368,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
$20.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Official
|
||||
</th>
|
||||
@ -368,7 +384,8 @@ exports[`renders ./components/descriptions/demo/responsive.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Config Info
|
||||
</th>
|
||||
@ -479,7 +496,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Product
|
||||
</th>
|
||||
@ -490,7 +508,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
Cloud Database
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Billing
|
||||
</th>
|
||||
@ -501,7 +520,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
Prepaid
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
time
|
||||
</th>
|
||||
@ -516,7 +536,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Amount
|
||||
</th>
|
||||
@ -527,7 +548,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
$80.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Discount
|
||||
</th>
|
||||
@ -538,7 +560,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
$20.00
|
||||
</td>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Official
|
||||
</th>
|
||||
@ -553,7 +576,8 @@ exports[`renders ./components/descriptions/demo/size.md correctly 1`] = `
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Config Info
|
||||
</th>
|
||||
@ -716,7 +740,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -725,8 +749,8 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
>
|
||||
UserName
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -735,8 +759,8 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
>
|
||||
Telephone
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -745,7 +769,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
>
|
||||
Live
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
@ -784,7 +808,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="2"
|
||||
>
|
||||
@ -793,8 +817,8 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
>
|
||||
Address
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -803,7 +827,7 @@ exports[`renders ./components/descriptions/demo/vertical.md correctly 1`] = `
|
||||
>
|
||||
Remark
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
@ -853,19 +877,19 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Product
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Billing Mode
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Automatic Renewal
|
||||
@ -897,14 +921,14 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Order time
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
colspan="3"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="2"
|
||||
>
|
||||
Usage Time
|
||||
</th>
|
||||
@ -920,7 +944,7 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
</td>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="3"
|
||||
colspan="2"
|
||||
>
|
||||
2019-04-24 18:00:00
|
||||
</td>
|
||||
@ -929,8 +953,8 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
colspan="5"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="3"
|
||||
>
|
||||
Status
|
||||
</th>
|
||||
@ -940,7 +964,7 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="5"
|
||||
colspan="3"
|
||||
>
|
||||
<span
|
||||
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
|
||||
@ -960,19 +984,19 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Negotiated Amount
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Discount
|
||||
</th>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="1"
|
||||
>
|
||||
Official Receipts
|
||||
@ -1004,8 +1028,8 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<th
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon"
|
||||
colspan="5"
|
||||
class="ant-descriptions-item-label"
|
||||
colspan="3"
|
||||
>
|
||||
Config Info
|
||||
</th>
|
||||
@ -1015,7 +1039,7 @@ exports[`renders ./components/descriptions/demo/vertical-border.md correctly 1`]
|
||||
>
|
||||
<td
|
||||
class="ant-descriptions-item-content"
|
||||
colspan="5"
|
||||
colspan="3"
|
||||
>
|
||||
Data disk type: MongoDB
|
||||
<br />
|
||||
|
@ -51,9 +51,6 @@ exports[`Descriptions Descriptions support style 1`] = `
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
<span
|
||||
class="ant-descriptions-item-label ant-descriptions-item-colon ant-descriptions-item-no-label"
|
||||
/>
|
||||
<span
|
||||
class="ant-descriptions-item-content"
|
||||
>
|
||||
@ -268,7 +265,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -277,7 +274,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
>
|
||||
Product
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
@ -296,7 +293,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -305,7 +302,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
>
|
||||
Billing
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
@ -324,7 +321,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -333,7 +330,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
>
|
||||
time
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
@ -352,7 +349,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
>
|
||||
<td
|
||||
<th
|
||||
class="ant-descriptions-item"
|
||||
colspan="1"
|
||||
>
|
||||
@ -361,7 +358,7 @@ exports[`Descriptions vertical layout 1`] = `
|
||||
>
|
||||
Amount
|
||||
</span>
|
||||
</td>
|
||||
</th>
|
||||
</tr>
|
||||
<tr
|
||||
class="ant-descriptions-row"
|
||||
|
@ -30,7 +30,7 @@ describe('Descriptions', () => {
|
||||
</Descriptions>,
|
||||
);
|
||||
expect(wrapper.find('tr')).toHaveLength(5);
|
||||
expect(wrapper.find('.ant-descriptions-item-no-label')).toHaveLength(1);
|
||||
expect(wrapper.find('.ant-descriptions-item-label')).toHaveLength(4);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
@ -71,7 +71,7 @@ describe('Descriptions', () => {
|
||||
<Descriptions.Item label="Amount">$80.00</Descriptions.Item>
|
||||
</Descriptions>,
|
||||
);
|
||||
expect(wrapper.instance().getColumn()).toBe(8);
|
||||
expect(wrapper.find('td').reduce((total, td) => total + td.props().colSpan, 0)).toBe(8);
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
@ -158,7 +158,7 @@ describe('Descriptions', () => {
|
||||
</Descriptions>,
|
||||
);
|
||||
|
||||
expect(wrapper.find('Col').key()).toBe('label-bamboo');
|
||||
expect(wrapper.find('Cell').key()).toBe('item-bamboo');
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/19887
|
||||
@ -178,4 +178,42 @@ describe('Descriptions', () => {
|
||||
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/20255
|
||||
it('columns 5 with customize', () => {
|
||||
const wrapper = mount(
|
||||
<Descriptions layout="vertical" column={4}>
|
||||
{/* 1 1 1 1 */}
|
||||
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
||||
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
||||
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
||||
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
||||
{/* 2 2 */}
|
||||
<Descriptions.Item label="bamboo" span={2}>
|
||||
bamboo
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="bamboo" span={2}>
|
||||
bamboo
|
||||
</Descriptions.Item>
|
||||
{/* 3 1 */}
|
||||
<Descriptions.Item label="bamboo" span={3}>
|
||||
bamboo
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="bamboo">bamboo</Descriptions.Item>
|
||||
</Descriptions>,
|
||||
);
|
||||
|
||||
function matchSpan(rowIndex, spans) {
|
||||
const tr = wrapper.find('tr').at(rowIndex);
|
||||
const tds = tr.find('th');
|
||||
expect(tds).toHaveLength(spans.length);
|
||||
tds.forEach((td, index) => {
|
||||
expect(td.props().colSpan).toEqual(spans[index]);
|
||||
});
|
||||
}
|
||||
|
||||
matchSpan(0, [1, 1, 1, 1]);
|
||||
matchSpan(2, [2, 2]);
|
||||
matchSpan(4, [3, 1]);
|
||||
});
|
||||
});
|
||||
|
@ -1,39 +1,95 @@
|
||||
/* eslint-disable react/no-array-index-key */
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import warning from '../_util/warning';
|
||||
import ResponsiveObserve, {
|
||||
Breakpoint,
|
||||
ScreenMap,
|
||||
responsiveArray,
|
||||
} from '../_util/responsiveObserve';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import Col from './Col';
|
||||
import warning from '../_util/warning';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import Row from './Row';
|
||||
import DescriptionsItem from './Item';
|
||||
|
||||
// https://github.com/smooth-code/react-flatten-children/
|
||||
function flattenChildren(children: React.ReactNode): JSX.Element[] {
|
||||
if (!children) {
|
||||
return [];
|
||||
const DEFAULT_COLUMN_MAP: Record<Breakpoint, number> = {
|
||||
xxl: 3,
|
||||
xl: 3,
|
||||
lg: 3,
|
||||
md: 3,
|
||||
sm: 2,
|
||||
xs: 1,
|
||||
};
|
||||
|
||||
function getColumn(column: DescriptionsProps['column'], screens: ScreenMap): number {
|
||||
if (typeof column === 'number') {
|
||||
return column;
|
||||
}
|
||||
return toArray(children).reduce((flatChildren: JSX.Element[], child: JSX.Element) => {
|
||||
if (child && child.type === React.Fragment) {
|
||||
return flatChildren.concat(flattenChildren(child.props.children));
|
||||
|
||||
if (typeof column === 'object') {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (screens[breakpoint] && column[breakpoint] !== undefined) {
|
||||
return column[breakpoint] || DEFAULT_COLUMN_MAP[breakpoint];
|
||||
}
|
||||
}
|
||||
flatChildren.push(child);
|
||||
return flatChildren;
|
||||
}, []);
|
||||
}
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
export interface DescriptionsItemProps {
|
||||
prefixCls?: string;
|
||||
className?: string;
|
||||
label?: React.ReactNode;
|
||||
children: React.ReactNode;
|
||||
span?: number;
|
||||
function getFilledItem(
|
||||
node: React.ReactElement,
|
||||
span: number | undefined,
|
||||
rowRestCol: number,
|
||||
): React.ReactElement {
|
||||
let clone = node;
|
||||
|
||||
if (span === undefined || span > rowRestCol) {
|
||||
clone = React.cloneElement(node, {
|
||||
span: rowRestCol,
|
||||
});
|
||||
warning(
|
||||
span === undefined,
|
||||
'Descriptions',
|
||||
'Sum of column `span` in a line not match `column` of Descriptions.',
|
||||
);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
const DescriptionsItem: React.SFC<DescriptionsItemProps> = ({ children }) =>
|
||||
children as JSX.Element;
|
||||
function getRows(children: React.ReactNode, column: number) {
|
||||
const childNodes = toArray(children).filter(n => n);
|
||||
const rows: React.ReactElement[][] = [];
|
||||
|
||||
let tmpRow: React.ReactElement[] = [];
|
||||
let rowRestCol = column;
|
||||
|
||||
childNodes.forEach((node, index) => {
|
||||
const span: number | undefined = node.props?.span;
|
||||
const mergedSpan = span || 1;
|
||||
|
||||
// Additional handle last one
|
||||
if (index === childNodes.length - 1) {
|
||||
tmpRow.push(getFilledItem(node, span, rowRestCol));
|
||||
rows.push(tmpRow);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mergedSpan < rowRestCol) {
|
||||
rowRestCol -= mergedSpan;
|
||||
tmpRow.push(node);
|
||||
} else {
|
||||
tmpRow.push(getFilledItem(node, mergedSpan, rowRestCol));
|
||||
rows.push(tmpRow);
|
||||
rowRestCol = column;
|
||||
tmpRow = [];
|
||||
}
|
||||
});
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
export interface DescriptionsProps {
|
||||
prefixCls?: string;
|
||||
@ -48,245 +104,73 @@ export interface DescriptionsProps {
|
||||
colon?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert children into `column` groups.
|
||||
* @param children: DescriptionsItem
|
||||
* @param column: number
|
||||
*/
|
||||
const generateChildrenRows = (
|
||||
children: React.ReactNode,
|
||||
column: number,
|
||||
): React.ReactElement<DescriptionsItemProps>[][] => {
|
||||
const rows: React.ReactElement<DescriptionsItemProps>[][] = [];
|
||||
let columns: React.ReactElement<DescriptionsItemProps>[] | null = null;
|
||||
let leftSpans: number;
|
||||
function Descriptions({
|
||||
prefixCls: customizePrefixCls,
|
||||
title,
|
||||
column = DEFAULT_COLUMN_MAP,
|
||||
colon = true,
|
||||
bordered,
|
||||
layout,
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
size,
|
||||
}: DescriptionsProps) {
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
|
||||
const [screens, setScreens] = React.useState<ScreenMap>({});
|
||||
const mergedColumn = getColumn(column, screens);
|
||||
|
||||
const itemNodes = flattenChildren(children);
|
||||
itemNodes.forEach((node: React.ReactElement<DescriptionsItemProps>, index: number) => {
|
||||
let itemNode = node;
|
||||
|
||||
if (!columns) {
|
||||
leftSpans = column;
|
||||
columns = [];
|
||||
rows.push(columns);
|
||||
}
|
||||
|
||||
// Always set last span to align the end of Descriptions
|
||||
const lastItem = index === itemNodes.length - 1;
|
||||
let lastSpanSame = true;
|
||||
if (lastItem) {
|
||||
lastSpanSame = !itemNode.props.span || itemNode.props.span === leftSpans;
|
||||
itemNode = React.cloneElement(itemNode, {
|
||||
span: leftSpans,
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate left fill span
|
||||
const { span = 1 } = itemNode.props;
|
||||
columns.push(itemNode);
|
||||
leftSpans -= span;
|
||||
|
||||
if (leftSpans <= 0) {
|
||||
columns = null;
|
||||
|
||||
warning(
|
||||
leftSpans === 0 && lastSpanSame,
|
||||
'Descriptions',
|
||||
'Sum of column `span` in a line not match `column` of Descriptions.',
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
const renderRow = (
|
||||
children: React.ReactElement<DescriptionsItemProps>[],
|
||||
index: number,
|
||||
{ prefixCls }: { prefixCls: string },
|
||||
bordered: boolean,
|
||||
layout: 'horizontal' | 'vertical',
|
||||
colon: boolean,
|
||||
) => {
|
||||
const renderCol = (
|
||||
colItem: React.ReactElement<DescriptionsItemProps>,
|
||||
type: 'label' | 'content',
|
||||
idx: number,
|
||||
) => {
|
||||
return (
|
||||
<Col
|
||||
child={colItem}
|
||||
bordered={bordered}
|
||||
colon={colon}
|
||||
type={type}
|
||||
key={`${type}-${colItem.key || idx}`}
|
||||
layout={layout}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const cloneChildren: JSX.Element[] = [];
|
||||
const cloneContentChildren: JSX.Element[] = [];
|
||||
flattenChildren(children).forEach(
|
||||
(childrenItem: React.ReactElement<DescriptionsItemProps>, idx: number) => {
|
||||
cloneChildren.push(renderCol(childrenItem, 'label', idx));
|
||||
if (layout === 'vertical') {
|
||||
cloneContentChildren.push(renderCol(childrenItem, 'content', idx));
|
||||
} else if (bordered) {
|
||||
cloneChildren.push(renderCol(childrenItem, 'content', idx));
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
if (layout === 'vertical') {
|
||||
return [
|
||||
<tr className={`${prefixCls}-row`} key={`label-${index}`}>
|
||||
{cloneChildren}
|
||||
</tr>,
|
||||
<tr className={`${prefixCls}-row`} key={`content-${index}`}>
|
||||
{cloneContentChildren}
|
||||
</tr>,
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<tr className={`${prefixCls}-row`} key={index}>
|
||||
{cloneChildren}
|
||||
</tr>
|
||||
);
|
||||
};
|
||||
|
||||
const defaultColumnMap = {
|
||||
xxl: 3,
|
||||
xl: 3,
|
||||
lg: 3,
|
||||
md: 3,
|
||||
sm: 2,
|
||||
xs: 1,
|
||||
};
|
||||
|
||||
class Descriptions extends React.Component<
|
||||
DescriptionsProps,
|
||||
{
|
||||
screens: ScreenMap;
|
||||
}
|
||||
> {
|
||||
static defaultProps: DescriptionsProps = {
|
||||
size: 'default',
|
||||
column: defaultColumnMap,
|
||||
};
|
||||
|
||||
static Item: typeof DescriptionsItem = DescriptionsItem;
|
||||
|
||||
state: {
|
||||
screens: ScreenMap;
|
||||
} = {
|
||||
screens: {},
|
||||
};
|
||||
|
||||
token: string;
|
||||
|
||||
componentDidMount() {
|
||||
const { column } = this.props;
|
||||
this.token = ResponsiveObserve.subscribe(screens => {
|
||||
// Responsive
|
||||
React.useEffect(() => {
|
||||
const token = ResponsiveObserve.subscribe(newScreens => {
|
||||
if (typeof column !== 'object') {
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
screens,
|
||||
});
|
||||
setScreens(newScreens);
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ResponsiveObserve.unsubscribe(this.token);
|
||||
}
|
||||
return () => {
|
||||
ResponsiveObserve.unsubscribe(token);
|
||||
};
|
||||
}, []);
|
||||
|
||||
getColumn(): number {
|
||||
const { column } = this.props;
|
||||
if (typeof column === 'object') {
|
||||
for (let i = 0; i < responsiveArray.length; i++) {
|
||||
const breakpoint: Breakpoint = responsiveArray[i];
|
||||
if (this.state.screens[breakpoint] && column[breakpoint] !== undefined) {
|
||||
return column[breakpoint] || defaultColumnMap[breakpoint];
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the configuration is not an object, it is a number, return number
|
||||
if (typeof column === 'number') {
|
||||
return column as number;
|
||||
}
|
||||
// If it is an object, but no response is found, this happens only in the test.
|
||||
// Maybe there are some strange environments
|
||||
return 3;
|
||||
}
|
||||
// Children
|
||||
const rows = getRows(children, mergedColumn);
|
||||
|
||||
render() {
|
||||
return (
|
||||
<ConfigConsumer>
|
||||
{({ getPrefixCls, direction }: ConfigConsumerProps) => {
|
||||
const {
|
||||
className,
|
||||
prefixCls: customizePrefixCls,
|
||||
title,
|
||||
size,
|
||||
children,
|
||||
bordered = false,
|
||||
layout = 'horizontal',
|
||||
colon = true,
|
||||
style,
|
||||
} = this.props;
|
||||
const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
|
||||
return (
|
||||
<div
|
||||
className={classNames(prefixCls, className, {
|
||||
[`${prefixCls}-${size}`]: size && size !== 'default',
|
||||
[`${prefixCls}-bordered`]: !!bordered,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
})}
|
||||
style={style}
|
||||
>
|
||||
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
||||
|
||||
const column = this.getColumn();
|
||||
const cloneChildren = flattenChildren(children)
|
||||
.map((child: React.ReactElement<DescriptionsItemProps>) => {
|
||||
if (React.isValidElement(child)) {
|
||||
return React.cloneElement(child, {
|
||||
prefixCls,
|
||||
});
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.filter((node: React.ReactElement) => node);
|
||||
|
||||
const childrenArray: Array<React.ReactElement<
|
||||
DescriptionsItemProps
|
||||
>[]> = generateChildrenRows(cloneChildren, column);
|
||||
return (
|
||||
<div
|
||||
className={classNames(prefixCls, className, {
|
||||
[`${prefixCls}-${size}`]: size !== 'default',
|
||||
[`${prefixCls}-bordered`]: !!bordered,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
})}
|
||||
style={style}
|
||||
>
|
||||
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
||||
<div className={`${prefixCls}-view`}>
|
||||
<table>
|
||||
<tbody>
|
||||
{childrenArray.map((child, index) =>
|
||||
renderRow(
|
||||
child,
|
||||
index,
|
||||
{
|
||||
prefixCls,
|
||||
},
|
||||
bordered,
|
||||
layout,
|
||||
colon,
|
||||
),
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</ConfigConsumer>
|
||||
);
|
||||
}
|
||||
<div className={`${prefixCls}-view`}>
|
||||
<table>
|
||||
<tbody>
|
||||
{rows.map((row, index) => (
|
||||
<Row
|
||||
key={index}
|
||||
index={index}
|
||||
colon={colon}
|
||||
prefixCls={prefixCls}
|
||||
vertical={layout === 'vertical'}
|
||||
bordered={bordered}
|
||||
>
|
||||
{row}
|
||||
</Row>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Descriptions.Item = DescriptionsItem;
|
||||
|
||||
export default Descriptions;
|
||||
|
@ -130,7 +130,7 @@
|
||||
"rc-tree-select": "~3.0.0-alpha.5",
|
||||
"rc-trigger": "~4.0.0-rc.0",
|
||||
"rc-upload": "~3.0.0-alpha.0",
|
||||
"rc-util": "^4.17.0",
|
||||
"rc-util": "^4.20.0",
|
||||
"rc-virtual-list": "^0.0.0-alpha.25",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"scroll-into-view-if-needed": "^2.2.20",
|
||||
|
Loading…
Reference in New Issue
Block a user