diff --git a/components/descriptions/Row.tsx b/components/descriptions/Row.tsx index 230925993d..2242c0a0bb 100644 --- a/components/descriptions/Row.tsx +++ b/components/descriptions/Row.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; +import type { DescriptionsItemType } from '.'; import Cell from './Cell'; import type { DescriptionsContextProps } from './DescriptionsContext'; import DescriptionsContext from './DescriptionsContext'; -import type { DescriptionsItemProps } from './Item'; interface CellConfig { component: string | [string, string]; @@ -12,7 +12,7 @@ interface CellConfig { } function renderCells( - items: React.ReactElement[], + items: DescriptionsItemType[], { colon, prefixCls, bordered }: RowProps, { component, @@ -26,16 +26,14 @@ function renderCells( return items.map( ( { - props: { - label, - children, - prefixCls: itemPrefixCls = prefixCls, - className, - style, - labelStyle, - contentStyle, - span = 1, - }, + label, + children, + prefixCls: itemPrefixCls = prefixCls, + className, + style, + labelStyle, + contentStyle, + span = 1, key, }, index, @@ -89,7 +87,7 @@ function renderCells( export interface RowProps { prefixCls: string; vertical: boolean; - row: React.ReactElement[]; + row: DescriptionsItemType[]; bordered?: boolean; colon: boolean; index: number; diff --git a/components/descriptions/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/descriptions/__tests__/__snapshots__/demo-extend.test.ts.snap index bb32c5b55d..d2699f7fda 100644 --- a/components/descriptions/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/descriptions/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -523,7 +523,7 @@ exports[`renders components/descriptions/demo/component-token.tsx extend context colspan="1" > - time + Time - time + Time `; -exports[`renders components/descriptions/demo/responsive.tsx extend context correctly 1`] = ` -
+exports[`renders components/descriptions/demo/jsx.tsx extend context correctly 1`] = ` +
-
- Responsive Descriptions -
+ User Info
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + UserName + + + Zhou Maomao + +
+
+
+ + Telephone + + + 1810000000 + +
+
+
+ + Live + + + Hangzhou, Zhejiang + +
+
+
+ + Remark + + + empty + +
+
+
+ + Address + + + No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China + +
+
+
+
+`; + +exports[`renders components/descriptions/demo/responsive.tsx extend context correctly 1`] = ` +
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - Product - - - - Cloud Database - -
- - Billing - - - - Prepaid - -
- - time - - - - 18:00:00 - -
- - Amount - - - - $80.00 - -
- - Discount - - - - $20.00 - -
- - Official - - - - $60.00 - -
- - Config Info - - - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
+ Responsive Descriptions
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Product + + + + Cloud Database + +
+ + Billing + + + + Prepaid + +
+ + Time + + + + 18:00:00 + +
+ + Amount + + + + $80.00 + +
+ + Discount + + + + $20.00 + +
+ + Official + + + + $60.00 + +
+ + Config Info + + + + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+
+
+
`; @@ -1125,7 +1263,7 @@ exports[`renders components/descriptions/demo/size.tsx extend context correctly colspan="1" > - time + Time - time + Time - time + Time - time + Time `; -exports[`renders components/descriptions/demo/responsive.tsx correctly 1`] = ` -
+exports[`renders components/descriptions/demo/jsx.tsx correctly 1`] = ` +
-
- Responsive Descriptions -
+ User Info
+
+
+ + + + + + + + + + + + +
+
+ + UserName + + + Zhou Maomao + +
+
+
+ + Telephone + + + 1810000000 + +
+
+
+ + Live + + + Hangzhou, Zhejiang + +
+
+
+ + Remark + + + empty + +
+
+
+ + Address + + + No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China + +
+
+
+
+`; + +exports[`renders components/descriptions/demo/responsive.tsx correctly 1`] = ` +
+
- - - - - - - - - - - - - - - - - - - - - - - -
- - Product - - - - Cloud Database - - - - Billing - - - - Prepaid - - - - time - - - - 18:00:00 - -
- - Amount - - - - $80.00 - - - - Discount - - - - $20.00 - - - - Official - - - - $60.00 - -
- - Config Info - - - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
+ Responsive Descriptions
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + Product + + + + Cloud Database + + + + Billing + + + + Prepaid + + + + Time + + + + 18:00:00 + +
+ + Amount + + + + $80.00 + + + + Discount + + + + $20.00 + + + + Official + + + + $60.00 + +
+ + Config Info + + + + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+
+
+
`; @@ -1037,7 +1163,7 @@ exports[`renders components/descriptions/demo/size.tsx correctly 1`] = ` colspan="1" > - time + Time - time + Time `; +exports[`Descriptions should items work 1`] = ` +
+
+
+ + + + + + + + + + + + +
+
+ + UserName + + + Zhou Maomao + +
+
+
+ + Telephone + + + 1810000000 + +
+
+
+ + Live + + + Hangzhou, Zhejiang + +
+
+
+
+
+`; + exports[`Descriptions should work with React Fragment 1`] = `
{ ); expect(container.querySelectorAll('.ant-descriptions-small')).toHaveLength(1); }); + + it('should items work', () => { + const { container } = render( + , + ); + expect(container.querySelector('.ant-descriptions-item')).toBeTruthy(); + expect(container.querySelectorAll('.ant-descriptions-item')).toHaveLength(3); + expect(container).toMatchSnapshot(); + }); }); diff --git a/components/descriptions/demo/basic.tsx b/components/descriptions/demo/basic.tsx index af67ab4f0c..547510b919 100644 --- a/components/descriptions/demo/basic.tsx +++ b/components/descriptions/demo/basic.tsx @@ -1,16 +1,35 @@ -import React from 'react'; import { Descriptions } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; -const App: React.FC = () => ( - - Zhou Maomao - 1810000000 - Hangzhou, Zhejiang - empty - - No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China - - -); +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'UserName', + children: 'Zhou Maomao', + }, + { + key: '2', + label: 'Telephone', + children: '1810000000', + }, + { + key: '3', + label: 'Live', + children: 'Hangzhou, Zhejiang', + }, + { + key: '4', + label: 'Remark', + children: 'empty', + }, + { + key: '5', + label: 'Address', + children: 'No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China', + }, +]; + +const App: React.FC = () => ; export default App; diff --git a/components/descriptions/demo/border.tsx b/components/descriptions/demo/border.tsx index cf9708c6f1..1383514175 100644 --- a/components/descriptions/demo/border.tsx +++ b/components/descriptions/demo/border.tsx @@ -1,36 +1,77 @@ -import React from 'react'; import { Badge, Descriptions } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; -const App: React.FC = () => ( - - Cloud Database - Prepaid - YES - 2018-04-24 18:00:00 - - 2019-04-24 18:00:00 - - - - - $80.00 - $20.00 - $60.00 - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
-
-); +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing Mode', + children: 'Prepaid', + }, + { + key: '3', + label: 'Automatic Renewal', + children: 'YES', + }, + { + key: '4', + label: 'Order time', + children: '2018-04-24 18:00:00', + }, + { + key: '5', + label: 'Usage Time', + children: '2019-04-24 18:00:00', + span: 2, + }, + { + key: '6', + label: 'Status', + children: , + span: 3, + }, + { + key: '7', + label: 'Negotiated Amount', + children: '$80.00', + }, + { + key: '8', + label: 'Discount', + children: '$20.00', + }, + { + key: '9', + label: 'Official Receipts', + children: '$60.00', + }, + { + key: '10', + label: 'Config Info', + children: ( + <> + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+ + ), + }, +]; + +const App: React.FC = () => ; export default App; diff --git a/components/descriptions/demo/component-token.tsx b/components/descriptions/demo/component-token.tsx index 4336ae1fd9..5bc9189981 100644 --- a/components/descriptions/demo/component-token.tsx +++ b/components/descriptions/demo/component-token.tsx @@ -1,7 +1,93 @@ import type { RadioChangeEvent } from 'antd'; import { Button, ConfigProvider, Descriptions, Radio } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; import React, { useState } from 'react'; +const borderedItems: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing', + children: 'Prepaid', + }, + { + key: '3', + label: 'Time', + children: '18:00:00', + }, + { + key: '4', + label: 'Amount', + children: '$80.00', + }, + { + key: '5', + label: 'Discount', + children: '$20.00', + }, + { + key: '6', + label: 'Official', + children: '$60.00', + }, + { + key: '7', + label: 'Config Info', + children: ( + <> + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+ + ), + }, +]; +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing', + children: 'Prepaid', + }, + { + key: '3', + label: 'Time', + children: '18:00:00', + }, + { + key: '4', + label: 'Amount', + children: '$80.00', + }, + { + key: '5', + label: 'Discount', + children: '$20.00', + }, + { + key: '6', + label: 'Official', + children: '$60.00', + }, +]; + const App: React.FC = () => { const [size, setSize] = useState<'default' | 'middle' | 'small'>('default'); @@ -33,38 +119,21 @@ const App: React.FC = () => {

- extra color: blue
}> - Cloud Database - Prepaid - 18:00:00 - $80.00 - $20.00 - $60.00 - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
- + extra color: blue
} + items={borderedItems} + />

- Edit}> - Cloud Database - Prepaid - 18:00:00 - $80.00 - $20.00 - $60.00 - + Edit} + items={items} + />
); diff --git a/components/descriptions/demo/jsx.md b/components/descriptions/demo/jsx.md new file mode 100644 index 0000000000..6cd0446161 --- /dev/null +++ b/components/descriptions/demo/jsx.md @@ -0,0 +1,7 @@ +## zh-CN + +JSX 风格演示。 + +## en-US + +JSX Style Demo. diff --git a/components/descriptions/demo/jsx.tsx b/components/descriptions/demo/jsx.tsx new file mode 100644 index 0000000000..1290370f53 --- /dev/null +++ b/components/descriptions/demo/jsx.tsx @@ -0,0 +1,16 @@ +import { Descriptions } from 'antd'; +import React from 'react'; + +const App: React.FC = () => ( + + Zhou Maomao + 1810000000 + Hangzhou, Zhejiang + empty + + No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China + + +); + +export default App; diff --git a/components/descriptions/demo/responsive.tsx b/components/descriptions/demo/responsive.tsx index ffd50c7959..2307e7abde 100644 --- a/components/descriptions/demo/responsive.tsx +++ b/components/descriptions/demo/responsive.tsx @@ -1,20 +1,43 @@ -import React from 'react'; import { Descriptions } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; -const App: React.FC = () => ( -
- - Cloud Database - Prepaid - 18:00:00 - $80.00 - $20.00 - $60.00 - +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing', + children: 'Prepaid', + }, + { + key: '3', + label: 'Time', + children: '18:00:00', + }, + { + key: '4', + label: 'Amount', + children: '$80.00', + }, + { + key: '5', + label: 'Discount', + children: '$20.00', + }, + { + key: '6', + label: 'Official', + children: '$60.00', + }, + { + key: '7', + label: 'Config Info', + children: ( + <> Data disk type: MongoDB
Database version: 3.4 @@ -26,9 +49,19 @@ const App: React.FC = () => ( Replication factor: 3
Region: East China 1 -
-
-
+
+ + ), + }, +]; + +const App: React.FC = () => ( + ); export default App; diff --git a/components/descriptions/demo/size.tsx b/components/descriptions/demo/size.tsx index 349265df87..ce65bdb1c7 100644 --- a/components/descriptions/demo/size.tsx +++ b/components/descriptions/demo/size.tsx @@ -1,6 +1,93 @@ -import React, { useState } from 'react'; import type { RadioChangeEvent } from 'antd'; import { Button, Descriptions, Radio } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React, { useState } from 'react'; + +const borderedItems: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing', + children: 'Prepaid', + }, + { + key: '3', + label: 'Time', + children: '18:00:00', + }, + { + key: '4', + label: 'Amount', + children: '$80.00', + }, + { + key: '5', + label: 'Discount', + children: '$20.00', + }, + { + key: '6', + label: 'Official', + children: '$60.00', + }, + { + key: '7', + label: 'Config Info', + children: ( + <> + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+ + ), + }, +]; + +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing', + children: 'Prepaid', + }, + { + key: '3', + label: 'Time', + children: '18:00:00', + }, + { + key: '4', + label: 'Amount', + children: '$80.00', + }, + { + key: '5', + label: 'Discount', + children: '$20.00', + }, + { + key: '6', + label: 'Official', + children: '$60.00', + }, +]; const App: React.FC = () => { const [size, setSize] = useState<'default' | 'middle' | 'small'>('default'); @@ -24,38 +111,16 @@ const App: React.FC = () => { title="Custom Size" size={size} extra={} - > - Cloud Database - Prepaid - 18:00:00 - $80.00 - $20.00 - $60.00 - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
-
+ items={borderedItems} + />

- Edit}> - Cloud Database - Prepaid - 18:00:00 - $80.00 - $20.00 - $60.00 - + Edit} + items={items} + /> ); }; diff --git a/components/descriptions/demo/style.tsx b/components/descriptions/demo/style.tsx index 4db6b60cb2..afc5be7b80 100644 --- a/components/descriptions/demo/style.tsx +++ b/components/descriptions/demo/style.tsx @@ -1,11 +1,52 @@ -import React, { useState } from 'react'; import { Descriptions, Divider, Radio, Switch } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React, { useState } from 'react'; const labelStyle: React.CSSProperties = { background: 'red' }; const contentStyle: React.CSSProperties = { background: 'green' }; type LayoutType = 'horizontal' | 'vertical' | undefined; +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + labelStyle, + contentStyle, + }, + { + key: '2', + label: 'Billing Mode', + children: 'Prepaid', + }, + { + key: '3', + label: 'Automatic Renewal', + children: 'YES', + }, +]; + +const rootStyleItems: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing Mode', + children: 'Prepaid', + }, + { + key: '3', + label: 'Automatic Renewal', + children: 'YES', + labelStyle: { color: 'orange' }, + contentStyle: { color: 'blue' }, + }, +]; + const App: React.FC = () => { const [border, setBorder] = useState(true); const [layout, setLayout] = useState('horizontal' as LayoutType); @@ -24,13 +65,7 @@ const App: React.FC = () => { vertical - - - Cloud Database - - Prepaid - YES - + { contentStyle={contentStyle} bordered={border} layout={layout} - > - Cloud Database - Prepaid - - YES - - + items={rootStyleItems} + /> ); }; diff --git a/components/descriptions/demo/text.tsx b/components/descriptions/demo/text.tsx index e215ce6576..2a1b45216b 100644 --- a/components/descriptions/demo/text.tsx +++ b/components/descriptions/demo/text.tsx @@ -1,5 +1,6 @@ -import React from 'react'; import { Badge, Descriptions, Table } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; const dataSource = [ { @@ -34,42 +35,86 @@ const columns = [ }, ]; -const App: React.FC = () => ( - - Cloud Database - Billing Mode}> - Prepaid - - YES - 2018-04-24 18:00:00 - - 2019-04-24 18:00:00 - - - - - $80.00 - $20.00 - $60.00 - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
- $60.00 - - - - -); +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label:
Billing Mode
, + children: 'Prepaid', + }, + { + key: '3', + label: 'Automatic Renewal', + children: 'YES', + }, + { + key: '4', + label: 'Order time', + children: '2018-04-24 18:00:00', + }, + { + key: '5', + label: 'Usage Time', + span: 2, + children: '2019-04-24 18:00:00', + }, + { + key: '6', + label: 'Status', + span: 3, + children: , + }, + { + key: '7', + label: 'Negotiated Amount', + children: '$80.00', + }, + { + key: '8', + label: 'Discount', + children: '$20.00', + }, + { + key: '9', + label: 'Official Receipts', + children: '$60.00', + }, + { + key: '10', + label: 'Config Info', + children: ( + <> + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+ + ), + }, + { + key: '11', + label: 'Official Receipts', + children: '$60.00', + }, + { + key: '12', + label: 'Config Info', + children:
, + }, +]; + +const App: React.FC = () => ; export default App; diff --git a/components/descriptions/demo/vertical-border.tsx b/components/descriptions/demo/vertical-border.tsx index 5738741445..e174ac1e27 100644 --- a/components/descriptions/demo/vertical-border.tsx +++ b/components/descriptions/demo/vertical-border.tsx @@ -1,36 +1,79 @@ -import React from 'react'; import { Badge, Descriptions } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; + +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'Product', + children: 'Cloud Database', + }, + { + key: '2', + label: 'Billing Mode', + children: 'Prepaid', + }, + { + key: '3', + label: 'Automatic Renewal', + children: 'YES', + }, + { + key: '4', + label: 'Order time', + children: '2018-04-24 18:00:00', + }, + { + key: '5', + label: 'Usage Time', + span: 2, + children: '2019-04-24 18:00:00', + }, + { + key: '6', + label: 'Status', + span: 3, + children: , + }, + { + key: '7', + label: 'Negotiated Amount', + children: '$80.00', + }, + { + key: '8', + label: 'Discount', + children: '$20.00', + }, + { + key: '9', + label: 'Official Receipts', + children: '$60.00', + }, + { + key: '10', + label: 'Config Info', + children: ( + <> + Data disk type: MongoDB +
+ Database version: 3.4 +
+ Package: dds.mongo.mid +
+ Storage space: 10 GB +
+ Replication factor: 3 +
+ Region: East China 1 +
+ + ), + }, +]; const App: React.FC = () => ( - - Cloud Database - Prepaid - YES - 2018-04-24 18:00:00 - - 2019-04-24 18:00:00 - - - - - $80.00 - $20.00 - $60.00 - - Data disk type: MongoDB -
- Database version: 3.4 -
- Package: dds.mongo.mid -
- Storage space: 10 GB -
- Replication factor: 3 -
- Region: East China 1 -
-
-
+ ); export default App; diff --git a/components/descriptions/demo/vertical.tsx b/components/descriptions/demo/vertical.tsx index 24bc1ba9af..14fb707d5f 100644 --- a/components/descriptions/demo/vertical.tsx +++ b/components/descriptions/demo/vertical.tsx @@ -1,16 +1,36 @@ -import React from 'react'; import { Descriptions } from 'antd'; +import type { DescriptionsProps } from 'antd/es/descriptions'; +import React from 'react'; -const App: React.FC = () => ( - - Zhou Maomao - 1810000000 - Hangzhou, Zhejiang - - No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China - - empty - -); +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'UserName', + children: 'Zhou Maomao', + }, + { + key: '2', + label: 'Telephone', + children: '1810000000', + }, + { + key: '3', + label: 'Live', + children: 'Hangzhou, Zhejiang', + }, + { + key: '4', + label: 'Address', + span: 2, + children: 'No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China', + }, + { + key: '5', + label: 'Remark', + children: 'empty', + }, +]; + +const App: React.FC = () => ; export default App; diff --git a/components/descriptions/hooks/useRow.ts b/components/descriptions/hooks/useRow.ts new file mode 100644 index 0000000000..40e4b05039 --- /dev/null +++ b/components/descriptions/hooks/useRow.ts @@ -0,0 +1,80 @@ +import toArray from 'rc-util/lib/Children/toArray'; +import type React from 'react'; +import { useMemo } from 'react'; +import type { DescriptionsItemType } from '..'; +import warning from '../../_util/warning'; + +function getFilledItem( + rowItem: DescriptionsItemType, + rowRestCol: number, + span?: number, +): DescriptionsItemType { + let clone = rowItem; + + if (span === undefined || span > rowRestCol) { + clone = { + ...rowItem, + span: rowRestCol, + }; + warning( + span === undefined, + 'Descriptions', + 'Sum of column `span` in a line not match `column` of Descriptions.', + ); + } + return clone; +} + +// Convert children into items +const transChildren2Items = (childNodes?: React.ReactNode) => + toArray(childNodes).map((node) => node?.props); + +// Calculate the sum of span in a row +function getCalcRows(rowItems: DescriptionsItemType[], mergedColumn: number) { + const rows: DescriptionsItemType[][] = []; + let tmpRow: DescriptionsItemType[] = []; + let rowRestCol = mergedColumn; + + rowItems + .filter((n) => n) + .forEach((rowItem, index) => { + const span = rowItem?.span; + const mergedSpan = span || 1; + + // Additional handle last one + if (index === rowItems.length - 1) { + tmpRow.push(getFilledItem(rowItem, rowRestCol, span)); + rows.push(tmpRow); + return; + } + + if (mergedSpan < rowRestCol) { + rowRestCol -= mergedSpan; + tmpRow.push(rowItem); + } else { + tmpRow.push(getFilledItem(rowItem, rowRestCol, mergedSpan)); + rows.push(tmpRow); + rowRestCol = mergedColumn; + tmpRow = []; + } + }); + + return rows; +} + +const useRow = ( + mergedColumn: number, + items?: DescriptionsItemType[], + children?: React.ReactNode, +) => { + const rows = useMemo(() => { + if (Array.isArray(items)) { + return getCalcRows(items, mergedColumn); + } + return getCalcRows(transChildren2Items(children), mergedColumn); + }, [items, children, mergedColumn]); + + return rows; +}; + +export default useRow; diff --git a/components/descriptions/index.en-US.md b/components/descriptions/index.en-US.md index accf36048e..2a4a985650 100644 --- a/components/descriptions/index.en-US.md +++ b/components/descriptions/index.en-US.md @@ -12,6 +12,52 @@ Display multiple read-only fields in groups. Commonly displayed on the details page. +```tsx | pure +// works when >= 5.8.0, recommended ✅ + +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'UserName', + children:

Zhou Maomao

, + }, + { + key: '2', + label: 'Telephone', + children:

1810000000

, + }, + { + key: '3', + label: 'Live', + children:

Hangzhou, Zhejiang

, + }, + { + key: '4', + label: 'Remark', + children:

empty

, + }, + { + key: '5', + label: 'Address', + children:

No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China

, + }, +]; + +; + +// works when <5.8.0 , deprecated when >=5.8.0 🙅🏻‍♀️ + + + Zhou Maomao + 1810000000 + Hangzhou, Zhejiang + empty + + No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China + +; +``` + ## Examples @@ -23,6 +69,7 @@ Commonly displayed on the details page. Vertical Vertical border Customize label & wrapper style +JSX demo Component Token ## API @@ -36,6 +83,7 @@ Commonly displayed on the details page. | column | The number of `DescriptionItems` in a row,could be a number or a object like `{ xs: 8, sm: 16, md: 24}`,(Only set `bordered={true}` to take effect) | number \| [Record](https://github.com/ant-design/ant-design/blob/84ca0d23ae52e4f0940f20b0e22eabe743f90dca/components/descriptions/index.tsx#L111C21-L111C56) | 3 | | | contentStyle | Customize content style | CSSProperties | - | 4.10.0 | | extra | The action area of the description list, placed at the top-right | ReactNode | - | 4.5.0 | +| items | Describe the contents of the list item | [DescriptionsItem](#descriptionitem)[] | - | 5.8.0 | | labelStyle | Customize label style | CSSProperties | - | 4.10.0 | | layout | Define description layout | `horizontal` \| `vertical` | `horizontal` | | | size | Set the size of the list. Can be set to `middle`,`small`, or not filled | `default` \| `middle` \| `small` | - | | diff --git a/components/descriptions/index.tsx b/components/descriptions/index.tsx index 3c9c82e2b8..6fc7edec2b 100644 --- a/components/descriptions/index.tsx +++ b/components/descriptions/index.tsx @@ -2,17 +2,16 @@ /* eslint-disable react/no-array-index-key */ import classNames from 'classnames'; -import toArray from 'rc-util/lib/Children/toArray'; import * as React from 'react'; -import { cloneElement } from '../_util/reactNode'; import type { Breakpoint, ScreenMap } from '../_util/responsiveObserver'; import useResponsiveObserver, { responsiveArray } from '../_util/responsiveObserver'; -import warning from '../_util/warning'; import { ConfigContext } from '../config-provider'; import useSize from '../config-provider/hooks/useSize'; import DescriptionsContext from './DescriptionsContext'; +import type { DescriptionsItemProps } from './Item'; import DescriptionsItem from './Item'; import Row from './Row'; +import useRow from './hooks/useRow'; import useStyle from './style'; const DEFAULT_COLUMN_MAP: Record = { @@ -41,63 +40,14 @@ function getColumn(column: DescriptionsProps['column'], screens: ScreenMap): num return 3; } -function getFilledItem( - node: React.ReactElement, - rowRestCol: number, - span?: number, -): React.ReactElement { - let clone = node; - - if (span === undefined || span > rowRestCol) { - clone = cloneElement(node, { - span: rowRestCol, - }); - warning( - span === undefined, - 'Descriptions', - 'Sum of column `span` in a line not match `column` of Descriptions.', - ); - } - - return clone; -} - -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 = node.props?.span; - const mergedSpan = span || 1; - - // Additional handle last one - if (index === childNodes.length - 1) { - tmpRow.push(getFilledItem(node, rowRestCol, span)); - rows.push(tmpRow); - return; - } - - if (mergedSpan < rowRestCol) { - rowRestCol -= mergedSpan; - tmpRow.push(node); - } else { - tmpRow.push(getFilledItem(node, rowRestCol, mergedSpan)); - rows.push(tmpRow); - rowRestCol = column; - tmpRow = []; - } - }); - - return rows; -} - interface CompoundedComponent { Item: typeof DescriptionsItem; } +export interface DescriptionsItemType extends DescriptionsItemProps { + key?: React.Key; +} + export interface DescriptionsProps { prefixCls?: string; className?: string; @@ -105,6 +55,9 @@ export interface DescriptionsProps { style?: React.CSSProperties; bordered?: boolean; size?: 'middle' | 'small' | 'default'; + /** + * @deprecated use `items` instead + */ children?: React.ReactNode; title?: React.ReactNode; extra?: React.ReactNode; @@ -113,6 +66,7 @@ export interface DescriptionsProps { colon?: boolean; labelStyle?: React.CSSProperties; contentStyle?: React.CSSProperties; + items?: DescriptionsItemType[]; } const Descriptions: React.FC & CompoundedComponent = (props) => { @@ -131,6 +85,7 @@ const Descriptions: React.FC & CompoundedComponent = (props) size: customizeSize, labelStyle, contentStyle, + items, ...restProps } = props; const { getPrefixCls, direction, descriptions } = React.useContext(ConfigContext); @@ -139,6 +94,7 @@ const Descriptions: React.FC & CompoundedComponent = (props) const mergedColumn = getColumn(column, screens); const mergedSize = useSize(customizeSize); + const rows = useRow(mergedColumn, items, children); const [wrapSSR, hashId] = useStyle(prefixCls); const responsiveObserver = useResponsiveObserver(); @@ -157,8 +113,7 @@ const Descriptions: React.FC & CompoundedComponent = (props) }; }, []); - // Children - const rows = getRows(children, mergedColumn); + // ======================== Render ======================== const contextValue = React.useMemo( () => ({ labelStyle, contentStyle }), [labelStyle, contentStyle], diff --git a/components/descriptions/index.zh-CN.md b/components/descriptions/index.zh-CN.md index 32aaab90e9..3c30f61968 100644 --- a/components/descriptions/index.zh-CN.md +++ b/components/descriptions/index.zh-CN.md @@ -13,6 +13,52 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*d27AQJrowGAAAA 常见于详情页的信息展示。 +```tsx | pure +// >= 5.8.0 可用,推荐的写法 ✅ + +const items: DescriptionsProps['items'] = [ + { + key: '1', + label: 'UserName', + children:

Zhou Maomao

, + }, + { + key: '2', + label: 'Telephone', + children:

1810000000

, + }, + { + key: '3', + label: 'Live', + children:

Hangzhou, Zhejiang

, + }, + { + key: '4', + label: 'Remark', + children:

empty

, + }, + { + key: '5', + label: 'Address', + children:

No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China

, + }, +]; + +; + +// <5.8.0 可用,>=5.8.0 时不推荐 🙅🏻‍♀️ + + + Zhou Maomao + 1810000000 + Hangzhou, Zhejiang + empty + + No. 18, Wantang Road, Xihu District, Hangzhou, Zhejiang, China + +; +``` + ## 代码演示 @@ -24,6 +70,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*d27AQJrowGAAAA 垂直 垂直带边框的 自定义 label & wrapper 样式 +JSX demo 组件 Token ## API @@ -37,6 +84,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*d27AQJrowGAAAA | column | 一行的 `DescriptionItems` 数量,可以写成像素值或支持响应式的对象写法 `{ xs: 8, sm: 16, md: 24}` | number \| [Record](https://github.com/ant-design/ant-design/blob/84ca0d23ae52e4f0940f20b0e22eabe743f90dca/components/descriptions/index.tsx#L111C21-L111C56) | 3 | | | contentStyle | 自定义内容样式 | CSSProperties | - | 4.10.0 | | extra | 描述列表的操作区域,显示在右上方 | ReactNode | - | 4.5.0 | +| items | 描述列表项内容 | [DescriptionsItem](#descriptionitem)[] | - | 5.8.0 | | labelStyle | 自定义标签样式 | CSSProperties | - | 4.10.0 | | layout | 描述布局 | `horizontal` \| `vertical` | `horizontal` | | | size | 设置列表的大小。可以设置为 `middle` 、`small`, 或不填(只有设置 `bordered={true}` 生效) | `default` \| `middle` \| `small` | - | |