feat: config-provider support divider className and style properties (#43042)

* feat: config-provider support divider className and style properties

* fix: simple ts definition

* fix: merge style & className

* fix: fix space className

* feat: optimize type definition

* feat: optimize type definition

* feat: add version

* test: update test

* test: update test

* fix: fix type

* fix: fix api sort

* fix: fix docs

* docs: add another api table

* Apply suggestions from code review

---------

Co-authored-by: MadCcc <1075746765@qq.com>
This commit is contained in:
muxin 2023-06-19 19:30:16 +08:00 committed by GitHub
parent 1fb8fc57d3
commit 785115c580
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 158 additions and 97 deletions

View File

@ -7,7 +7,6 @@ import { fireEvent, render } from '../../../tests/utils';
import Button from '../../button'; import Button from '../../button';
import Input from '../../input'; import Input from '../../input';
import Select from '../../select'; import Select from '../../select';
import Space from '../../space';
import Table from '../../table'; import Table from '../../table';
describe('ConfigProvider', () => { describe('ConfigProvider', () => {
@ -124,78 +123,4 @@ describe('ConfigProvider', () => {
expect(rendered).toBeTruthy(); expect(rendered).toBeTruthy();
expect(cacheRenderEmpty).toBeFalsy(); expect(cacheRenderEmpty).toBeFalsy();
}); });
it('Should Space classNames works', () => {
const { container } = render(
<ConfigProvider
space={{
classNames: {
item: 'test-classNames',
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space-item.test-classNames')).toBeTruthy();
});
it('Should Space className works', () => {
const { container } = render(
<ConfigProvider
space={{
className: 'test-classNames',
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space.test-classNames')).toBeTruthy();
});
it('Should Space styles works', () => {
const { container } = render(
<ConfigProvider
space={{
styles: {
item: {
color: 'red',
},
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space-item')?.getAttribute('style')).toEqual(
'margin-right: 8px; color: red;',
);
});
it('Should Space style works', () => {
const { container } = render(
<ConfigProvider
space={{
style: {
color: 'red',
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space')?.getAttribute('style')).toEqual('color: red;');
});
}); });

View File

@ -0,0 +1,110 @@
import React from 'react';
import ConfigProvider from '..';
import { render } from '../../../tests/utils';
import Divider from '../../divider';
import Space from '../../space';
describe('ConfigProvider support style and className props', () => {
it('Should Space classNames works', () => {
const { container } = render(
<ConfigProvider
space={{
classNames: {
item: 'test-classNames',
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space-item.test-classNames')).toBeTruthy();
});
it('Should Space className works', () => {
const { container } = render(
<ConfigProvider
space={{
className: 'test-classNames',
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space.test-classNames')).toBeTruthy();
});
it('Should Space styles works', () => {
const { container } = render(
<ConfigProvider
space={{
styles: {
item: {
color: 'red',
},
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space-item')?.getAttribute('style')).toEqual(
'margin-right: 8px; color: red;',
);
});
it('Should Space style works', () => {
const { container } = render(
<ConfigProvider
space={{
style: {
color: 'red',
},
}}
>
<Space>
<span>Text1</span>
<span>Text2</span>
</Space>
</ConfigProvider>,
);
expect(container.querySelector('.ant-space')?.getAttribute('style')).toEqual('color: red;');
});
it('Should Divider className works', () => {
const { container } = render(
<ConfigProvider
divider={{
className: 'config-provider-className',
}}
>
<Divider />
</ConfigProvider>,
);
expect(container.querySelector('.ant-divider')).toHaveClass('config-provider-className');
});
it('Should Divider style works', () => {
const { container } = render(
<ConfigProvider
divider={{
style: {
color: 'red',
height: 80,
},
}}
>
<Divider />
</ConfigProvider>,
);
expect(container.querySelector('.ant-divider'))?.toHaveStyle({ color: 'red', height: '80px' });
});
});

View File

@ -36,15 +36,16 @@ export interface ThemeConfig {
inherit?: boolean; inherit?: boolean;
} }
interface componentStyleConfig { export interface componentStyleConfig {
className?: string; className?: string;
style?: React.CSSProperties; style?: React.CSSProperties;
}
export interface ButtonConfig extends componentStyleConfig {
classNames?: ButtonProps['classNames']; classNames?: ButtonProps['classNames'];
styles?: ButtonProps['styles']; styles?: ButtonProps['styles'];
} }
export interface ButtonConfig extends componentStyleConfig {}
export type PopupOverflow = 'viewport' | 'scroll'; export type PopupOverflow = 'viewport' | 'scroll';
export interface ConfigConsumerProps { export interface ConfigConsumerProps {
@ -87,6 +88,7 @@ export interface ConfigConsumerProps {
showSearch?: boolean; showSearch?: boolean;
}; };
button?: ButtonConfig; button?: ButtonConfig;
divider?: componentStyleConfig;
} }
const defaultGetPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => { const defaultGetPrefixCls = (suffixCls?: string, customizePrefixCls?: string) => {

View File

@ -55,19 +55,14 @@ Some components use dynamic style to support wave effect. You can config `csp` p
| componentSize | Config antd component size | `small` \| `middle` \| `large` | - | | | componentSize | Config antd component size | `small` \| `middle` \| `large` | - | |
| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | | | csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | |
| direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | | direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
| popupMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 5.5.0 |
| popupOverflow | Select like component popup logic. Can set to show in viewport or follow window scroll | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | | | getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | |
| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 | | getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 |
| iconPrefixCls | Set icon prefix className | string | `anticon` | 4.11.0 | | iconPrefixCls | Set icon prefix className | string | `anticon` | 4.11.0 |
| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 |
| select | Set Select common props | { showSearch?: boolean } | - | |
| button | Set Select common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| locale | Language package setting, you can find the packages in [antd/locale](http://unpkg.com/antd/locale/) | object | - | | | locale | Language package setting, you can find the packages in [antd/locale](http://unpkg.com/antd/locale/) | object | - | |
| popupMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 5.5.0 |
| popupOverflow | Select like component popup logic. Can set to show in viewport or follow window scroll | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
| prefixCls | Set prefix className | string | `ant` | | | prefixCls | Set prefix className | string | `ant` | |
| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | | | renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | |
| space | Set Space common props, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: { item: string }, styles?: { item: React.CSSProperties } } | - | 5.6.0 |
| theme | Set theme, ref [Customize Theme](/docs/react/customize-theme) | - | - | 5.0.0 | | theme | Set theme, ref [Customize Theme](/docs/react/customize-theme) | - | - | 5.0.0 |
| virtual | Disable virtual scroll when set to `false` | boolean | - | 4.3.0 | | virtual | Disable virtual scroll when set to `false` | boolean | - | 4.3.0 |
@ -102,6 +97,17 @@ const {
| componentDisabled | antd component disabled state | boolean | - | 5.3.0 | | componentDisabled | antd component disabled state | boolean | - | 5.3.0 |
| componentSize | antd component size state | `small` \| `middle` \| `large` | - | 5.3.0 | | componentSize | antd component size state | `small` \| `middle` \| `large` | - | 5.3.0 |
### Component Config
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| button | Set Button common props | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| divider | Set Divider common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 |
| select | Set Select common props | { showSearch?: boolean } | - | |
| space | Set Space common props, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: { item: string }, styles?: { item: React.CSSProperties } } | - | 5.6.0 |
## FAQ ## FAQ
#### How to contribute a new language? #### How to contribute a new language?

View File

@ -19,6 +19,7 @@ import { DesignTokenContext } from '../theme/internal';
import defaultSeedToken from '../theme/themes/seed'; import defaultSeedToken from '../theme/themes/seed';
import type { import type {
ButtonConfig, ButtonConfig,
componentStyleConfig,
ConfigConsumerProps, ConfigConsumerProps,
CSPConfig, CSPConfig,
DirectionType, DirectionType,
@ -38,8 +39,8 @@ import SizeContext, { SizeContextProvider } from './SizeContext';
import useStyle from './style'; import useStyle from './style';
/** /**
* Since too many feedback using static method like `Modal.confirm` not getting theme, * Since too many feedback using static method like `Modal.confirm` not getting theme, we record the
* we record the theme register info here to help developer get warning info. * theme register info here to help developer get warning info.
*/ */
let existThemeConfig = false; let existThemeConfig = false;
@ -136,6 +137,7 @@ export interface ConfigProviderProps {
popupOverflow?: PopupOverflow; popupOverflow?: PopupOverflow;
theme?: ThemeConfig; theme?: ThemeConfig;
button?: ButtonConfig; button?: ButtonConfig;
divider?: componentStyleConfig;
} }
interface ProviderChildrenProps extends ConfigProviderProps { interface ProviderChildrenProps extends ConfigProviderProps {
@ -223,6 +225,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
iconPrefixCls: customIconPrefixCls, iconPrefixCls: customIconPrefixCls,
theme, theme,
componentDisabled, componentDisabled,
divider,
} = props; } = props;
// =================================== Warning =================================== // =================================== Warning ===================================
@ -272,6 +275,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
getPrefixCls, getPrefixCls,
iconPrefixCls, iconPrefixCls,
theme: mergedTheme, theme: mergedTheme,
divider,
}; };
const config = { const config = {

View File

@ -56,19 +56,14 @@ export default Demo;
| componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | | | componentSize | 设置 antd 组件大小 | `small` \| `middle` \| `large` | - | |
| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | | | csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | |
| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | | | direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 5.5.0 |
| popupOverflow | Select 类组件弹层展示逻辑,默认为可视区域滚动,可配置成滚动区域滚动 | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), requiredMark?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
| getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | | | getPopupContainer | 弹出框Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | |
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 | | getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
| iconPrefixCls | 设置图标统一样式前缀 | string | `anticon` | 4.11.0 | | iconPrefixCls | 设置图标统一样式前缀 | string | `anticon` | 4.11.0 |
| input | 设置 Input 组件的通用属性 | { autoComplete?: string } | - | 4.2.0 |
| select | 设置 Select 组件的通用属性 | { showSearch?: boolean } | - | |
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| locale | 语言包配置,语言包可到 [antd/locale](http://unpkg.com/antd/locale/) 目录下寻找 | object | - | | | locale | 语言包配置,语言包可到 [antd/locale](http://unpkg.com/antd/locale/) 目录下寻找 | object | - | |
| popupMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 5.5.0 |
| popupOverflow | Select 类组件弹层展示逻辑,默认为可视区域滚动,可配置成滚动区域滚动 | 'viewport' \| 'scroll' <InlinePopover previewURL="https://user-images.githubusercontent.com/5378891/230344474-5b9f7e09-0a5d-49e8-bae8-7d2abed6c837.png"></InlinePopover> | 'viewport' | 5.5.0 |
| prefixCls | 设置统一样式前缀 | string | `ant` | | | prefixCls | 设置统一样式前缀 | string | `ant` | |
| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty-cn) | function(componentName: string): ReactNode | - | | | renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty-cn) | function(componentName: string): ReactNode | - | |
| space | 设置 Space 的通用属性,参考 [Space](/components/space-cn) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: { item: string }, styles?: { item: React.CSSProperties } } | - | 5.6.0 |
| theme | 设置主题,参考 [定制主题](/docs/react/customize-theme-cn) | - | - | 5.0.0 | | theme | 设置主题,参考 [定制主题](/docs/react/customize-theme-cn) | - | - | 5.0.0 |
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 | | virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 |
@ -104,6 +99,17 @@ const {
| componentDisabled | antd 组件禁用状态 | boolean | - | 5.3.0 | | componentDisabled | antd 组件禁用状态 | boolean | - | 5.3.0 |
| componentSize | antd 组件大小状态 | `small` \| `middle` \| `large` | - | 5.3.0 | | componentSize | antd 组件大小状态 | `small` \| `middle` \| `large` | - | 5.3.0 |
### 组件配置
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| button | 设置 Button 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: { icon: string }, styles?: { icon: React.CSSProperties } } | - | 5.6.0 |
| divider | 设置 Divider 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), requiredMark?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0 |
| input | 设置 Input 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| select | 设置 Select 组件的通用属性 | { showSearch?: boolean } | - | |
| space | 设置 Space 的通用属性,参考 [Space](/components/space-cn) | { size: `small` \| `middle` \| `large` \| `number`, className?: string, style?: React.CSSProperties, classNames?: { item: string }, styles?: { item: React.CSSProperties } } | - | 5.6.0 |
## FAQ ## FAQ
#### 如何增加一个新的语言包? #### 如何增加一个新的语言包?

View File

@ -19,7 +19,7 @@ export interface DividerProps {
} }
const Divider: React.FC<DividerProps> = (props) => { const Divider: React.FC<DividerProps> = (props) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext); const { getPrefixCls, direction, divider } = React.useContext(ConfigContext);
const { const {
prefixCls: customizePrefixCls, prefixCls: customizePrefixCls,
@ -31,6 +31,7 @@ const Divider: React.FC<DividerProps> = (props) => {
children, children,
dashed, dashed,
plain, plain,
style,
...restProps ...restProps
} = props; } = props;
const prefixCls = getPrefixCls('divider', customizePrefixCls); const prefixCls = getPrefixCls('divider', customizePrefixCls);
@ -42,6 +43,7 @@ const Divider: React.FC<DividerProps> = (props) => {
const hasCustomMarginRight = orientation === 'right' && orientationMargin != null; const hasCustomMarginRight = orientation === 'right' && orientationMargin != null;
const classString = classNames( const classString = classNames(
prefixCls, prefixCls,
divider?.className,
hashId, hashId,
`${prefixCls}-${type}`, `${prefixCls}-${type}`,
{ {
@ -82,7 +84,12 @@ const Divider: React.FC<DividerProps> = (props) => {
} }
return wrapSSR( return wrapSSR(
<div className={classString} {...restProps} role="separator"> <div
className={classString}
style={{ ...divider?.style, ...style }}
{...restProps}
role="separator"
>
{children && type !== 'vertical' && ( {children && type !== 'vertical' && (
<span className={`${prefixCls}-inner-text`} style={innerStyle}> <span className={`${prefixCls}-inner-text`} style={innerStyle}>
{children} {children}

View File

@ -76,13 +76,14 @@ const Space = React.forwardRef<HTMLDivElement, SpaceProps>((props, ref) => {
const cn = classNames( const cn = classNames(
prefixCls, prefixCls,
space?.className,
hashId, hashId,
`${prefixCls}-${direction}`, `${prefixCls}-${direction}`,
{ {
[`${prefixCls}-rtl`]: directionConfig === 'rtl', [`${prefixCls}-rtl`]: directionConfig === 'rtl',
[`${prefixCls}-align-${mergedAlign}`]: mergedAlign, [`${prefixCls}-align-${mergedAlign}`]: mergedAlign,
}, },
className ?? space?.className, className,
rootClassName, rootClassName,
); );