mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-22 17:13:27 +08:00
feat: ConfigProvider support classNames
and styles
for Descriptions (#52120)
Some checks are pending
Publish Any Commit / build (push) Waiting to run
🔀 Sync mirror to Gitee / mirror (push) Waiting to run
✅ test / lint (push) Waiting to run
✅ test / test-react-legacy (16, 1/2) (push) Waiting to run
✅ test / test-react-legacy (16, 2/2) (push) Waiting to run
✅ test / test-react-legacy (17, 1/2) (push) Waiting to run
✅ test / test-react-legacy (17, 2/2) (push) Waiting to run
✅ test / test-node (push) Waiting to run
✅ test / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test / test-coverage (push) Blocked by required conditions
✅ test / build (push) Waiting to run
✅ test / test lib/es module (es, 1/2) (push) Waiting to run
✅ test / test lib/es module (es, 2/2) (push) Waiting to run
✅ test / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run
Some checks are pending
Publish Any Commit / build (push) Waiting to run
🔀 Sync mirror to Gitee / mirror (push) Waiting to run
✅ test / lint (push) Waiting to run
✅ test / test-react-legacy (16, 1/2) (push) Waiting to run
✅ test / test-react-legacy (16, 2/2) (push) Waiting to run
✅ test / test-react-legacy (17, 1/2) (push) Waiting to run
✅ test / test-react-legacy (17, 2/2) (push) Waiting to run
✅ test / test-node (push) Waiting to run
✅ test / test-react-latest (dom, 1/2) (push) Waiting to run
✅ test / test-react-latest (dom, 2/2) (push) Waiting to run
✅ test / test-react-latest-dist (dist, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist, 2/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 1/2) (push) Blocked by required conditions
✅ test / test-react-latest-dist (dist-min, 2/2) (push) Blocked by required conditions
✅ test / test-coverage (push) Blocked by required conditions
✅ test / build (push) Waiting to run
✅ test / test lib/es module (es, 1/2) (push) Waiting to run
✅ test / test lib/es module (es, 2/2) (push) Waiting to run
✅ test / test lib/es module (lib, 1/2) (push) Waiting to run
✅ test / test lib/es module (lib, 2/2) (push) Waiting to run
👁️ Visual Regression Persist Start / test image (push) Waiting to run
* draft * fix * fix * add header, title, extra * add border preview * update * update demo * add divider * update width * update SemanticPreview demo
This commit is contained in:
parent
3c1f56c99d
commit
0745996d65
@ -37,6 +37,7 @@ import type { RenderEmptyHandler } from './defaultRenderEmpty';
|
||||
import type { TooltipProps } from '../tooltip';
|
||||
import type { PopoverProps } from '../popover';
|
||||
import type { PopconfirmProps } from '../popconfirm';
|
||||
import type { DescriptionsProps } from '../descriptions';
|
||||
|
||||
export const defaultPrefixCls = 'ant';
|
||||
export const defaultIconPrefixCls = 'anticon';
|
||||
@ -136,6 +137,9 @@ export type MenuConfig = ComponentStyleConfig & Pick<MenuProps, 'expandIcon'>;
|
||||
|
||||
export type TourConfig = Pick<TourProps, 'closeIcon'>;
|
||||
|
||||
export type DescriptionsConfig = ComponentStyleConfig &
|
||||
Pick<DescriptionsProps, 'classNames' | 'styles'>;
|
||||
|
||||
export type ModalConfig = ComponentStyleConfig &
|
||||
Pick<ModalProps, 'classNames' | 'styles' | 'closeIcon' | 'closable'>;
|
||||
|
||||
@ -285,7 +289,7 @@ export interface ConfigConsumerProps {
|
||||
breadcrumb?: ComponentStyleConfig;
|
||||
menu?: MenuConfig;
|
||||
checkbox?: ComponentStyleConfig;
|
||||
descriptions?: ComponentStyleConfig;
|
||||
descriptions?: DescriptionsConfig;
|
||||
empty?: ComponentStyleConfig;
|
||||
badge?: BadgeConfig;
|
||||
radio?: ComponentStyleConfig;
|
||||
|
@ -123,7 +123,7 @@ const {
|
||||
| colorPicker | Set ColorPicker common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| datePicker | Set datePicker common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| rangePicker | Set rangePicker common props | { className?: string, style?: React.CSSProperties } | - | 5.11.0 |
|
||||
| descriptions | Set Descriptions common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| descriptions | Set Descriptions common props | { className?: string, style?: React.CSSProperties, classNames?: [DescriptionsProps\["classNames"\]](/components/descriptions#api), styles?: [DescriptionsProps\["styles"\]](/components/descriptions#api) } | - | 5.7.0, `classNames` and `styles`: 5.23.0 |
|
||||
| divider | Set Divider common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| drawer | Set Drawer common props | { className?: string, style?: React.CSSProperties, classNames?: [DrawerProps\["classNames"\]](/components/drawer#api), styles?: [DrawerProps\["styles"\]](/components/drawer#api), closeIcon?: ReactNode } | - | 5.7.0, `classNames` and `styles`: 5.10.0, `closeIcon`: 5.14.0 |
|
||||
| dropdown | Set Dropdown common props | { className?: string, style?: React.CSSProperties } | - | 5.11.0 |
|
||||
|
@ -125,7 +125,7 @@ const {
|
||||
| colorPicker | 设置 ColorPicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| datePicker | 设置 DatePicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| rangePicker | 设置 RangePicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.11.0 |
|
||||
| descriptions | 设置 Descriptions 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| descriptions | 设置 Descriptions 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [DescriptionsProps\["classNames"\]](/components/descriptions-cn#api), styles?: [DescriptionsProps\["styles"\]](/components/descriptions-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 5.23.0 |
|
||||
| divider | 设置 Divider 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
|
||||
| drawer | 设置 Drawer 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [DrawerProps\["classNames"\]](/components/drawer-cn#api), styles?: [DrawerProps\["styles"\]](/components/drawer-cn#api), closeIcon?: ReactNode } | - | 5.7.0, `classNames` 和 `styles`: 5.10.0, `closeIcon`: 5.14.0 |
|
||||
| dropdown | 设置 Dropdown 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.11.0 |
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import type { JSX } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import DescriptionsContext from './DescriptionsContext';
|
||||
|
||||
function notEmpty(val: any) {
|
||||
return val !== undefined && val !== null;
|
||||
@ -12,8 +13,18 @@ export interface CellProps {
|
||||
className?: string;
|
||||
component: string;
|
||||
style?: React.CSSProperties;
|
||||
/** @deprecated Please use `styles={{ label: {} }}` instead */
|
||||
labelStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `styles={{ content: {} }}` instead */
|
||||
contentStyle?: React.CSSProperties;
|
||||
styles?: {
|
||||
label?: React.CSSProperties;
|
||||
content?: React.CSSProperties;
|
||||
};
|
||||
classNames?: {
|
||||
label?: string;
|
||||
content?: string;
|
||||
};
|
||||
bordered?: boolean;
|
||||
label?: React.ReactNode;
|
||||
content?: React.ReactNode;
|
||||
@ -35,9 +46,12 @@ const Cell: React.FC<CellProps> = (props) => {
|
||||
content,
|
||||
colon,
|
||||
type,
|
||||
styles,
|
||||
} = props;
|
||||
|
||||
const Component = component as keyof JSX.IntrinsicElements;
|
||||
const descContext = React.useContext(DescriptionsContext);
|
||||
const { classNames: descriptionsClassNames } = descContext;
|
||||
|
||||
if (bordered) {
|
||||
return (
|
||||
@ -46,14 +60,16 @@ const Cell: React.FC<CellProps> = (props) => {
|
||||
{
|
||||
[`${itemPrefixCls}-item-label`]: type === 'label',
|
||||
[`${itemPrefixCls}-item-content`]: type === 'content',
|
||||
[`${descriptionsClassNames?.label}`]: type === 'label',
|
||||
[`${descriptionsClassNames?.content}`]: type === 'content',
|
||||
},
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
colSpan={span}
|
||||
>
|
||||
{notEmpty(label) && <span style={labelStyle}>{label}</span>}
|
||||
{notEmpty(content) && <span style={contentStyle}>{content}</span>}
|
||||
{notEmpty(label) && <span style={{ ...labelStyle, ...styles?.label }}>{label}</span>}
|
||||
{notEmpty(content) && <span style={{ ...labelStyle, ...styles?.content }}>{content}</span>}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
@ -67,16 +83,19 @@ const Cell: React.FC<CellProps> = (props) => {
|
||||
<div className={`${itemPrefixCls}-item-container`}>
|
||||
{(label || label === 0) && (
|
||||
<span
|
||||
className={classNames(`${itemPrefixCls}-item-label`, {
|
||||
className={classNames(`${itemPrefixCls}-item-label`, descriptionsClassNames?.label, {
|
||||
[`${itemPrefixCls}-item-no-colon`]: !colon,
|
||||
})}
|
||||
style={labelStyle}
|
||||
style={{ ...labelStyle, ...styles?.label }}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
)}
|
||||
{(content || content === 0) && (
|
||||
<span className={classNames(`${itemPrefixCls}-item-content`)} style={contentStyle}>
|
||||
<span
|
||||
className={classNames(`${itemPrefixCls}-item-content`, descriptionsClassNames?.content)}
|
||||
style={{ ...contentStyle, ...styles?.content }}
|
||||
>
|
||||
{content}
|
||||
</span>
|
||||
)}
|
||||
|
@ -1,8 +1,18 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface DescriptionsContextProps {
|
||||
/** @deprecated Please use `styles={{ label: {} }}` instead */
|
||||
labelStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `styles={{ content: {} }}` instead */
|
||||
contentStyle?: React.CSSProperties;
|
||||
styles?: {
|
||||
label?: React.CSSProperties;
|
||||
content?: React.CSSProperties;
|
||||
};
|
||||
classNames?: {
|
||||
label?: string;
|
||||
content?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const DescriptionsContext = React.createContext<DescriptionsContextProps>({});
|
||||
|
@ -5,8 +5,18 @@ export interface DescriptionsItemProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
label?: React.ReactNode;
|
||||
/** @deprecated Please use `styles={{ label: {} }}` instead */
|
||||
labelStyle?: React.CSSProperties;
|
||||
/** @deprecated Please use `styles={{ content: {} }}` instead */
|
||||
contentStyle?: React.CSSProperties;
|
||||
styles?: {
|
||||
label?: React.CSSProperties;
|
||||
content?: React.CSSProperties;
|
||||
};
|
||||
classNames?: {
|
||||
label?: string;
|
||||
content?: string;
|
||||
};
|
||||
children: React.ReactNode;
|
||||
span?: number;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ function renderCells(
|
||||
showContent,
|
||||
labelStyle: rootLabelStyle,
|
||||
contentStyle: rootContentStyle,
|
||||
styles: rootStyles,
|
||||
}: CellConfig & DescriptionsContextProps,
|
||||
) {
|
||||
return items.map(
|
||||
@ -36,6 +37,7 @@ function renderCells(
|
||||
contentStyle,
|
||||
span = 1,
|
||||
key,
|
||||
styles,
|
||||
},
|
||||
index,
|
||||
) => {
|
||||
@ -45,8 +47,20 @@ function renderCells(
|
||||
key={`${type}-${key || index}`}
|
||||
className={className}
|
||||
style={style}
|
||||
labelStyle={{ ...rootLabelStyle, ...labelStyle }}
|
||||
contentStyle={{ ...rootContentStyle, ...contentStyle }}
|
||||
styles={{
|
||||
label: {
|
||||
...rootLabelStyle,
|
||||
...rootStyles?.label,
|
||||
...labelStyle,
|
||||
...styles?.label,
|
||||
},
|
||||
content: {
|
||||
...rootContentStyle,
|
||||
...rootStyles?.content,
|
||||
...contentStyle,
|
||||
...styles?.content,
|
||||
},
|
||||
}}
|
||||
span={span}
|
||||
colon={colon}
|
||||
component={component}
|
||||
@ -63,7 +77,13 @@ function renderCells(
|
||||
<Cell
|
||||
key={`label-${key || index}`}
|
||||
className={className}
|
||||
style={{ ...rootLabelStyle, ...style, ...labelStyle }}
|
||||
style={{
|
||||
...rootLabelStyle,
|
||||
...rootStyles?.label,
|
||||
...style,
|
||||
...labelStyle,
|
||||
...styles?.label,
|
||||
}}
|
||||
span={1}
|
||||
colon={colon}
|
||||
component={component[0]}
|
||||
@ -75,7 +95,13 @@ function renderCells(
|
||||
<Cell
|
||||
key={`content-${key || index}`}
|
||||
className={className}
|
||||
style={{ ...rootContentStyle, ...style, ...contentStyle }}
|
||||
style={{
|
||||
...rootContentStyle,
|
||||
...rootStyles?.content,
|
||||
...style,
|
||||
...contentStyle,
|
||||
...styles?.content,
|
||||
}}
|
||||
span={span * 2 - 1}
|
||||
component={component[1]}
|
||||
itemPrefixCls={itemPrefixCls}
|
||||
|
@ -415,4 +415,83 @@ describe('Descriptions', () => {
|
||||
expect(wrapper.container.querySelectorAll('.ant-descriptions-item-label')).toHaveLength(1);
|
||||
expect(wrapper.container.querySelectorAll('.ant-descriptions-item-content')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should apply custom styles to Descriptions', () => {
|
||||
const customClassNames = {
|
||||
root: 'custom-root',
|
||||
header: 'custom-header',
|
||||
title: 'custom-title',
|
||||
extra: 'custom-extra',
|
||||
label: 'custom-label',
|
||||
content: 'custom-content',
|
||||
};
|
||||
|
||||
const customStyles = {
|
||||
root: { backgroundColor: 'red' },
|
||||
header: { backgroundColor: 'black' },
|
||||
title: { backgroundColor: 'yellow' },
|
||||
extra: { backgroundColor: 'purple' },
|
||||
label: { backgroundColor: 'blue' },
|
||||
content: { backgroundColor: 'green' },
|
||||
};
|
||||
|
||||
const { container } = render(
|
||||
<Descriptions
|
||||
classNames={customClassNames}
|
||||
styles={customStyles}
|
||||
extra={'extra'}
|
||||
title="User Info"
|
||||
items={[
|
||||
{
|
||||
key: '1',
|
||||
label: 'UserName',
|
||||
children: '1',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: 'UserName',
|
||||
children: '2',
|
||||
styles: {
|
||||
content: { color: 'yellow' },
|
||||
label: { color: 'orange' },
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
const rootElement = container.querySelector('.ant-descriptions') as HTMLElement;
|
||||
const headerElement = container.querySelector('.ant-descriptions-header') as HTMLElement;
|
||||
const titleElement = container.querySelector('.ant-descriptions-title') as HTMLElement;
|
||||
const extraElement = container.querySelector('.ant-descriptions-extra') as HTMLElement;
|
||||
const labelElement = container.querySelector('.ant-descriptions-item-label') as HTMLElement;
|
||||
const contentElement = container.querySelector('.ant-descriptions-item-content') as HTMLElement;
|
||||
const labelElements = container.querySelectorAll(
|
||||
'.ant-descriptions-item-label',
|
||||
) as NodeListOf<HTMLElement>;
|
||||
const contentElements = container.querySelectorAll(
|
||||
'.ant-descriptions-item-content',
|
||||
) as NodeListOf<HTMLElement>;
|
||||
|
||||
// check classNames
|
||||
expect(rootElement.classList).toContain('custom-root');
|
||||
expect(headerElement.classList).toContain('custom-header');
|
||||
expect(titleElement.classList).toContain('custom-title');
|
||||
expect(extraElement.classList).toContain('custom-extra');
|
||||
expect(labelElement.classList).toContain('custom-label');
|
||||
expect(contentElement.classList).toContain('custom-content');
|
||||
|
||||
// check styles
|
||||
expect(rootElement.style.backgroundColor).toBe('red');
|
||||
expect(headerElement.style.backgroundColor).toBe('black');
|
||||
expect(titleElement.style.backgroundColor).toBe('yellow');
|
||||
expect(extraElement.style.backgroundColor).toBe('purple');
|
||||
expect(labelElement.style.backgroundColor).toBe('blue');
|
||||
expect(contentElement.style.backgroundColor).toBe('green');
|
||||
|
||||
expect(labelElements[1].style.color).toBe('orange');
|
||||
expect(contentElements[1].style.color).toBe('yellow');
|
||||
expect(labelElements[0].style.color).not.toBe('orange');
|
||||
expect(contentElements[0].style.color).not.toBe('yellow');
|
||||
});
|
||||
});
|
||||
|
75
components/descriptions/demo/_semantic.tsx
Normal file
75
components/descriptions/demo/_semantic.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
import React from 'react';
|
||||
import { Button, Descriptions, DescriptionsProps, Divider, Switch } from 'antd';
|
||||
|
||||
import SemanticPreview from '../../../.dumi/components/SemanticPreview';
|
||||
import useLocale from '../../../.dumi/hooks/useLocale';
|
||||
|
||||
const locales = {
|
||||
cn: {
|
||||
root: '根节点',
|
||||
header: '头部元素',
|
||||
title: '标题元素',
|
||||
extra: '额外内容',
|
||||
label: '标签元素',
|
||||
content: '内容元素',
|
||||
},
|
||||
en: {
|
||||
root: 'root element',
|
||||
header: 'header element',
|
||||
title: 'title element',
|
||||
extra: 'extra element',
|
||||
label: 'label element',
|
||||
content: 'content element',
|
||||
},
|
||||
};
|
||||
|
||||
const items: DescriptionsProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: 'Telephone',
|
||||
children: '1810000000',
|
||||
},
|
||||
];
|
||||
|
||||
const BlockList: React.FC<React.PropsWithChildren> = (props: any) => {
|
||||
const divRef = React.useRef<HTMLDivElement>(null);
|
||||
const [bordered, setBordered] = React.useState(false);
|
||||
|
||||
const handleBorderChange = (checked: boolean) => {
|
||||
setBordered(checked);
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={divRef} style={{ width: '100%', height: '100%' }}>
|
||||
<Switch checked={bordered} onChange={handleBorderChange} /> Toggle Border
|
||||
<Divider />
|
||||
<Descriptions
|
||||
title="User Info"
|
||||
items={items}
|
||||
extra={<Button type="primary">Edit</Button>}
|
||||
bordered={bordered}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [locale] = useLocale(locales);
|
||||
return (
|
||||
<SemanticPreview
|
||||
semantics={[
|
||||
{ name: 'root', desc: locale.root, version: '5.23.0' },
|
||||
{ name: 'header', desc: locale.header, version: '5.23.0' },
|
||||
{ name: 'title', desc: locale.title, version: '5.23.0' },
|
||||
{ name: 'extra', desc: locale.extra, version: '5.23.0' },
|
||||
{ name: 'label', desc: locale.label, version: '5.23.0' },
|
||||
{ name: 'content', desc: locale.content, version: '5.23.0' },
|
||||
]}
|
||||
>
|
||||
<BlockList />
|
||||
</SemanticPreview>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
@ -12,8 +12,10 @@ const items: DescriptionsProps['items'] = [
|
||||
key: '1',
|
||||
label: 'Product',
|
||||
children: 'Cloud Database',
|
||||
labelStyle,
|
||||
contentStyle,
|
||||
styles: {
|
||||
label: labelStyle,
|
||||
content: contentStyle,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
@ -42,8 +44,10 @@ const rootStyleItems: DescriptionsProps['items'] = [
|
||||
key: '3',
|
||||
label: 'Automatic Renewal',
|
||||
children: 'YES',
|
||||
labelStyle: { color: 'orange' },
|
||||
contentStyle: { color: 'blue' },
|
||||
styles: {
|
||||
label: { color: 'orange' },
|
||||
content: { color: 'blue' },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@ -69,8 +73,10 @@ const App: React.FC = () => {
|
||||
<Divider />
|
||||
<Descriptions
|
||||
title="Root style"
|
||||
labelStyle={labelStyle}
|
||||
contentStyle={contentStyle}
|
||||
styles={{
|
||||
label: labelStyle,
|
||||
content: contentStyle,
|
||||
}}
|
||||
bordered={border}
|
||||
layout={layout}
|
||||
items={rootStyleItems}
|
||||
|
@ -103,6 +103,10 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
|
||||
> The number of span Description.Item. Span={2} takes up the width of two DescriptionItems. When both `style` and `labelStyle`(or `contentStyle`) configured, both of them will work. And next one will overwrite first when conflict.
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## Design Token
|
||||
|
||||
<ComponentTokenTable component="Descriptions"></ComponentTokenTable>
|
||||
|
@ -4,6 +4,7 @@ import classNames from 'classnames';
|
||||
|
||||
import type { Breakpoint } from '../_util/responsiveObserver';
|
||||
import { matchScreen } from '../_util/responsiveObserver';
|
||||
import { devUseWarning } from '../_util/warning';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import useSize from '../config-provider/hooks/useSize';
|
||||
import useBreakpoint from '../grid/hooks/useBreakpoint';
|
||||
@ -48,6 +49,22 @@ export interface DescriptionsProps {
|
||||
colon?: boolean;
|
||||
labelStyle?: React.CSSProperties;
|
||||
contentStyle?: React.CSSProperties;
|
||||
styles?: {
|
||||
root?: React.CSSProperties;
|
||||
header?: React.CSSProperties;
|
||||
title?: React.CSSProperties;
|
||||
extra?: React.CSSProperties;
|
||||
label?: React.CSSProperties;
|
||||
content?: React.CSSProperties;
|
||||
};
|
||||
classNames?: {
|
||||
root?: string;
|
||||
header?: string;
|
||||
title?: string;
|
||||
extra?: string;
|
||||
label?: string;
|
||||
content?: string;
|
||||
};
|
||||
items?: DescriptionsItemType[];
|
||||
id?: string;
|
||||
}
|
||||
@ -68,13 +85,25 @@ const Descriptions: React.FC<DescriptionsProps> & CompoundedComponent = (props)
|
||||
size: customizeSize,
|
||||
labelStyle,
|
||||
contentStyle,
|
||||
styles,
|
||||
items,
|
||||
classNames: descriptionsClassNames,
|
||||
...restProps
|
||||
} = props;
|
||||
const { getPrefixCls, direction, descriptions } = React.useContext(ConfigContext);
|
||||
const prefixCls = getPrefixCls('descriptions', customizePrefixCls);
|
||||
const screens = useBreakpoint();
|
||||
|
||||
// ============================== Warn ==============================
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const warning = devUseWarning('Descriptions');
|
||||
[
|
||||
['labelStyle', 'styles={{ label: {} }}'],
|
||||
['contentStyle', 'styles={{ content: {} }}'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
|
||||
});
|
||||
}
|
||||
// Column count
|
||||
const mergedColumn = React.useMemo(() => {
|
||||
if (typeof column === 'number') {
|
||||
@ -99,8 +128,19 @@ const Descriptions: React.FC<DescriptionsProps> & CompoundedComponent = (props)
|
||||
|
||||
// ======================== Render ========================
|
||||
const contextValue = React.useMemo(
|
||||
() => ({ labelStyle, contentStyle }),
|
||||
[labelStyle, contentStyle],
|
||||
() => ({
|
||||
labelStyle,
|
||||
contentStyle,
|
||||
styles: {
|
||||
content: { ...descriptions?.styles?.content, ...styles?.content },
|
||||
label: { ...descriptions?.styles?.label, ...styles?.label },
|
||||
},
|
||||
classNames: {
|
||||
label: classNames(descriptions?.classNames?.label, descriptionsClassNames?.label),
|
||||
content: classNames(descriptions?.classNames?.content, descriptionsClassNames?.content),
|
||||
},
|
||||
}),
|
||||
[labelStyle, contentStyle, styles, descriptionsClassNames, descriptions],
|
||||
);
|
||||
|
||||
return wrapCSSVar(
|
||||
@ -109,6 +149,8 @@ const Descriptions: React.FC<DescriptionsProps> & CompoundedComponent = (props)
|
||||
className={classNames(
|
||||
prefixCls,
|
||||
descriptions?.className,
|
||||
descriptions?.classNames?.root,
|
||||
descriptionsClassNames?.root,
|
||||
{
|
||||
[`${prefixCls}-${mergedSize}`]: mergedSize && mergedSize !== 'default',
|
||||
[`${prefixCls}-bordered`]: !!bordered,
|
||||
@ -119,13 +161,45 @@ const Descriptions: React.FC<DescriptionsProps> & CompoundedComponent = (props)
|
||||
hashId,
|
||||
cssVarCls,
|
||||
)}
|
||||
style={{ ...descriptions?.style, ...style }}
|
||||
style={{ ...descriptions?.style, ...descriptions?.styles?.root, ...styles?.root, ...style }}
|
||||
{...restProps}
|
||||
>
|
||||
{(title || extra) && (
|
||||
<div className={`${prefixCls}-header`}>
|
||||
{title && <div className={`${prefixCls}-title`}>{title}</div>}
|
||||
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
|
||||
<div
|
||||
className={classNames(
|
||||
`${prefixCls}-header`,
|
||||
descriptions?.classNames?.header,
|
||||
descriptionsClassNames?.header,
|
||||
)}
|
||||
style={{ ...descriptions?.styles?.header, ...styles?.header }}
|
||||
>
|
||||
{title && (
|
||||
<div
|
||||
className={classNames(
|
||||
`${prefixCls}-title`,
|
||||
descriptions?.classNames?.title,
|
||||
descriptionsClassNames?.title,
|
||||
)}
|
||||
style={{
|
||||
...descriptions?.styles?.title,
|
||||
...styles?.title,
|
||||
}}
|
||||
>
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
{extra && (
|
||||
<div
|
||||
className={classNames(
|
||||
`${prefixCls}-extra`,
|
||||
descriptions?.classNames?.extra,
|
||||
descriptionsClassNames?.extra,
|
||||
)}
|
||||
style={{ ...descriptions?.styles?.extra, ...styles?.extra }}
|
||||
>
|
||||
{extra}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -104,6 +104,10 @@ const items: DescriptionsProps['items'] = [
|
||||
|
||||
> span 是 Description.Item 的数量。 span={2} 会占用两个 DescriptionItem 的宽度。当同时配置 `style` 和 `labelStyle`(或 `contentStyle`)时,两者会同时作用。样式冲突时,后者会覆盖前者。
|
||||
|
||||
## Semantic DOM
|
||||
|
||||
<code src="./demo/_semantic.tsx" simplify="true"></code>
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component="Descriptions"></ComponentTokenTable>
|
||||
|
Loading…
Reference in New Issue
Block a user