Browse Source

feat: ConfigProvider.config support theme config (#42473)

* chore: static config of theme

* chore: static all method

* test: add test case

* docs: comment

* docs: more info

* test: update snapshot

* test: fix test logic
pull/42390/merge
二货爱吃白萝卜 2 years ago
committed by GitHub
parent
commit
43d7b9ca92
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      .dumi/theme/SiteThemeProvider.tsx
  2. 23
      components/config-provider/__tests__/static.test.ts
  3. 4
      components/config-provider/__tests__/theme.test.tsx
  4. 12
      components/config-provider/index.en-US.md
  5. 19
      components/config-provider/index.tsx
  6. 12
      components/config-provider/index.zh-CN.md
  7. 2
      components/message/__tests__/__snapshots__/demo-extend.test.ts.snap
  8. 2
      components/message/__tests__/__snapshots__/demo.test.ts.snap
  9. 4
      components/message/demo/info.md
  10. 4
      components/message/demo/info.tsx
  11. 2
      components/message/index.en-US.md
  12. 5
      components/message/index.tsx
  13. 2
      components/message/index.zh-CN.md
  14. 14
      components/modal/ConfirmDialog.tsx
  15. 8
      components/modal/confirm.tsx
  16. 4
      components/notification/demo/basic.md
  17. 2
      components/notification/index.en-US.md
  18. 3
      components/notification/index.tsx
  19. 2
      components/notification/index.zh-CN.md

20
.dumi/theme/SiteThemeProvider.tsx

@ -1,18 +1,24 @@
import type { FC } from 'react';
import React, { useContext } from 'react';
import { ConfigContext } from 'antd/es/config-provider';
import { ConfigProvider, theme as antdTheme } from 'antd';
import type { ThemeProviderProps } from 'antd-style';
import { ThemeProvider } from 'antd-style';
import { theme } from 'antd';
import type { FC } from 'react';
import React, { useContext } from 'react';
const SiteThemeProvider: FC<ThemeProviderProps> = ({ children, ...rest }) => {
const { getPrefixCls, iconPrefixCls } = useContext(ConfigContext);
const SiteThemeProvider: FC<ThemeProviderProps> = ({ children, theme, ...rest }) => {
const { getPrefixCls, iconPrefixCls } = useContext(ConfigProvider.ConfigContext);
const rootPrefixCls = getPrefixCls();
const { token } = theme.useToken();
const { token } = antdTheme.useToken();
React.useEffect(() => {
ConfigProvider.config({
theme,
});
}, [theme]);
return (
<ThemeProvider
{...rest}
theme={theme}
customToken={{
headerHeight: 64,
menuItemBorder: 2,

23
components/config-provider/__tests__/static.test.ts

@ -9,4 +9,27 @@ describe('ConfigProvider.config', () => {
});
expect(globalConfig().getRootPrefixCls()).toEqual('light');
});
it('theme', () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
expect(globalConfig().getTheme()).toBeFalsy();
ConfigProvider.config({
theme: {
infoColor: 'red',
},
});
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: ConfigProvider] `config` of css variable theme is not work in v5. Please use new `theme` config instead.',
);
ConfigProvider.config({
theme: {
token: {},
},
});
expect(globalConfig().getTheme()).toEqual({ token: {} });
});
});

4
components/config-provider/__tests__/theme.test.tsx

@ -49,7 +49,9 @@ describe('ConfigProvider.Theme', () => {
expect(canUseDom()).toBeFalsy();
ConfigProvider.config({
theme: {},
theme: {
infoColor: 'red',
},
});
expect(errorSpy).toHaveBeenCalledWith(

12
components/config-provider/index.en-US.md

@ -70,14 +70,18 @@ Some components use dynamic style to support wave effect. You can config `csp` p
| 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 |
### ConfigProvider.config() `4.13.0+`
### ConfigProvider.config()
Setting `Modal`、`Message`、`Notification` rootPrefixCls.
Setting `Modal`、`Message`、`Notification` static config. Not work on hooks.
```ts
ConfigProvider.config({
prefixCls: 'ant', // 4.13.0+
iconPrefixCls: 'anticon', // 4.17.0+
prefixCls: 'ant',
iconPrefixCls: 'anticon',
// 5.6.0+
// Please use hooks version first
theme: { token: { colorPrimary: 'red' } },
});
```

19
components/config-provider/index.tsx

@ -138,6 +138,7 @@ interface ProviderChildrenProps extends ConfigProviderProps {
export const defaultPrefixCls = 'ant';
let globalPrefixCls: string;
let globalIconPrefixCls: string;
let globalTheme: ThemeConfig;
function getGlobalPrefixCls() {
return globalPrefixCls || defaultPrefixCls;
@ -147,11 +148,15 @@ function getGlobalIconPrefixCls() {
return globalIconPrefixCls || defaultIconPrefixCls;
}
function isLegacyTheme(theme: Theme | ThemeConfig): theme is Theme {
return Object.keys(theme).some((key) => key.endsWith('Color'));
}
const setGlobalConfig = ({
prefixCls,
iconPrefixCls,
theme,
}: Pick<ConfigProviderProps, 'prefixCls' | 'iconPrefixCls'> & { theme?: Theme }) => {
}: Pick<ConfigProviderProps, 'prefixCls' | 'iconPrefixCls'> & { theme?: Theme | ThemeConfig }) => {
if (prefixCls !== undefined) {
globalPrefixCls = prefixCls;
}
@ -160,7 +165,16 @@ const setGlobalConfig = ({
}
if (theme) {
registerTheme(getGlobalPrefixCls(), theme);
if (isLegacyTheme(theme)) {
warning(
false,
'ConfigProvider',
'`config` of css variable theme is not work in v5. Please use new `theme` config instead.',
);
registerTheme(getGlobalPrefixCls(), theme);
} else {
globalTheme = theme;
}
}
};
@ -179,6 +193,7 @@ export const globalConfig = () => ({
// Fallback to default prefixCls
return getGlobalPrefixCls();
},
getTheme: () => globalTheme,
});
const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {

12
components/config-provider/index.zh-CN.md

@ -71,14 +71,18 @@ export default Demo;
| theme | 设置主题,参考 [定制主题](/docs/react/customize-theme-cn) | - | - | 5.0.0 |
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 |
### ConfigProvider.config() `4.13.0+`
### ConfigProvider.config()
设置 `Modal`、`Message`、`Notification` rootPrefixCls
设置 `Modal`、`Message`、`Notification` 静态方法配置,只会对非 hooks 的静态方法调用生效
```ts
ConfigProvider.config({
prefixCls: 'ant', // 4.13.0+
iconPrefixCls: 'anticon', // 4.17.0+
prefixCls: 'ant',
iconPrefixCls: 'anticon',
// 5.6.0+
// 请优先考虑使用 hooks 版本
theme: { token: { colorPrimary: 'red' } },
});
```

2
components/message/__tests__/__snapshots__/demo-extend.test.ts.snap

@ -76,7 +76,7 @@ exports[`renders components/message/demo/info.tsx extend context correctly 1`] =
type="button"
>
<span>
Display normal message
Static Method
</span>
</button>
`;

2
components/message/__tests__/__snapshots__/demo.test.ts.snap

@ -76,7 +76,7 @@ exports[`renders components/message/demo/info.tsx correctly 1`] = `
type="button"
>
<span>
Display normal message
Static Method
</span>
</button>
`;

4
components/message/demo/info.md

@ -1,7 +1,7 @@
## zh-CN
信息提醒反馈
静态方法无法消费 Context,推荐优先使用 Hooks 版本
## en-US
Normal message for information.
Static methods cannot consume Context. Please use hooks first.

4
components/message/demo/info.tsx

@ -1,5 +1,5 @@
import React from 'react';
import { Button, message } from 'antd';
import React from 'react';
const info = () => {
message.info('This is a normal message');
@ -7,7 +7,7 @@ const info = () => {
const App: React.FC = () => (
<Button type="primary" onClick={info}>
Display normal message
Static Method
</Button>
);

2
components/message/index.en-US.md

@ -26,7 +26,7 @@ Display global messages as feedback in response to user operations.
<code src="./demo/thenable.tsx">Promise interface</code>
<code src="./demo/custom-style.tsx">Customized style</code>
<code src="./demo/update.tsx">Update Message Content</code>
<code src="./demo/info.tsx">Normal prompt</code>
<code src="./demo/info.tsx">Static method (deprecated)</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
<code src="./demo/component-token.tsx" debug>Component Token</code>

5
components/message/index.tsx

@ -1,6 +1,7 @@
import { render } from 'rc-util/lib/React/render';
import * as React from 'react';
import ConfigProvider, { globalConfig, warnContext } from '../config-provider';
import PurePanel from './PurePanel';
import type {
ArgsProps,
ConfigOptions,
@ -9,7 +10,6 @@ import type {
NoticeType,
TypeOpen,
} from './interface';
import PurePanel from './PurePanel';
import useMessage, { useInternalMessage } from './useMessage';
import { wrapPromiseFn } from './util';
@ -102,6 +102,7 @@ const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
const global = globalConfig();
const rootPrefixCls = global.getRootPrefixCls();
const rootIconPrefixCls = global.getIconPrefixCls();
const theme = global.getTheme();
const sync = () => {
setMessageConfig(initializeMessageConfig);
@ -126,7 +127,7 @@ const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
});
return (
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={rootIconPrefixCls}>
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={rootIconPrefixCls} theme={theme}>
{holder}
</ConfigProvider>
);

2
components/message/index.zh-CN.md

@ -27,7 +27,7 @@ demo:
<code src="./demo/thenable.tsx">Promise 接口</code>
<code src="./demo/custom-style.tsx">自定义样式</code>
<code src="./demo/update.tsx">更新消息内容</code>
<code src="./demo/info.tsx">普通提示</code>
<code src="./demo/info.tsx">静态方法(不推荐)</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
<code src="./demo/component-token.tsx" debug>组件 Token</code>

14
components/modal/ConfirmDialog.tsx

@ -4,11 +4,12 @@ import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import InfoCircleFilled from '@ant-design/icons/InfoCircleFilled';
import classNames from 'classnames';
import * as React from 'react';
import ConfigProvider from '../config-provider';
import { useLocale } from '../locale';
import ActionButton from '../_util/ActionButton';
import { getTransitionName } from '../_util/motion';
import warning from '../_util/warning';
import type { ThemeConfig } from '../config-provider';
import ConfigProvider from '../config-provider';
import { useLocale } from '../locale';
import type { ModalFuncProps, ModalLocale } from './Modal';
import Dialog from './Modal';
@ -18,6 +19,7 @@ interface ConfirmDialogProps extends ModalFuncProps {
autoFocusButton?: null | 'ok' | 'cancel';
rootPrefixCls: string;
iconPrefixCls?: string;
theme?: ThemeConfig;
/** @private Internal Usage. Do not override this */
locale?: ModalLocale;
@ -143,6 +145,7 @@ const ConfirmDialog: React.FC<ConfirmDialogProps> = (props) => {
wrapClassName,
rootPrefixCls,
iconPrefixCls,
theme,
bodyStyle,
closable = false,
closeIcon,
@ -174,7 +177,12 @@ const ConfirmDialog: React.FC<ConfirmDialogProps> = (props) => {
);
return (
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={iconPrefixCls} direction={direction}>
<ConfigProvider
prefixCls={rootPrefixCls}
iconPrefixCls={iconPrefixCls}
direction={direction}
theme={theme}
>
<Dialog
prefixCls={prefixCls}
className={classString}

8
components/modal/confirm.tsx

@ -1,11 +1,11 @@
import { render as reactRender, unmount as reactUnmount } from 'rc-util/lib/React/render';
import * as React from 'react';
import { globalConfig, warnContext } from '../config-provider';
import warning from '../_util/warning';
import { globalConfig, warnContext } from '../config-provider';
import ConfirmDialog from './ConfirmDialog';
import type { ModalFuncProps } from './Modal';
import destroyFns from './destroyFns';
import { getConfirmLocale } from './locale';
import type { ModalFuncProps } from './Modal';
let defaultRootPrefixCls = '';
@ -60,11 +60,12 @@ export default function confirm(config: ModalFuncProps) {
*/
timeoutId = setTimeout(() => {
const runtimeLocale = getConfirmLocale();
const { getPrefixCls, getIconPrefixCls } = globalConfig();
const { getPrefixCls, getIconPrefixCls, getTheme } = globalConfig();
// because Modal.config  set rootPrefixCls, which is different from other components
const rootPrefixCls = getPrefixCls(undefined, getRootPrefixCls());
const prefixCls = customizePrefixCls || `${rootPrefixCls}-modal`;
const iconPrefixCls = getIconPrefixCls();
const theme = getTheme();
reactRender(
<ConfirmDialog
@ -74,6 +75,7 @@ export default function confirm(config: ModalFuncProps) {
iconPrefixCls={iconPrefixCls}
okText={okText}
locale={runtimeLocale}
theme={theme}
cancelText={cancelText || runtimeLocale.cancelText}
/>,
container,

4
components/notification/demo/basic.md

@ -1,7 +1,7 @@
## zh-CN
最简单的用法,4.5 秒后自动关闭
静态方法无法消费 Context,推荐优先使用 Hooks 版本
## en-US
The simplest usage that close the notification box after 4.5s.
Static methods cannot consume Context. Please use hooks first.

2
components/notification/index.en-US.md

@ -23,7 +23,6 @@ To display a notification message at any of the four corners of the viewport. Ty
<!-- prettier-ignore -->
<code src="./demo/hooks.tsx">Hooks usage (recommended)</code>
<code src="./demo/basic.tsx">Basic</code>
<code src="./demo/duration.tsx">Duration after which the notification box is closed</code>
<code src="./demo/with-icon.tsx">Notification with icon</code>
<code src="./demo/with-btn.tsx">Custom close button</code>
@ -31,6 +30,7 @@ To display a notification message at any of the four corners of the viewport. Ty
<code src="./demo/placement.tsx">Placement</code>
<code src="./demo/custom-style.tsx">Customized style</code>
<code src="./demo/update.tsx">Update Message Content</code>
<code src="./demo/basic.tsx">Static Method (deprecated)</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
## API

3
components/notification/index.tsx

@ -76,6 +76,7 @@ const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
const global = globalConfig();
const rootPrefixCls = global.getRootPrefixCls();
const rootIconPrefixCls = global.getIconPrefixCls();
const theme = global.getTheme();
const sync = () => {
const {
@ -114,7 +115,7 @@ const GlobalHolder = React.forwardRef<GlobalHolderRef, {}>((_, ref) => {
});
return (
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={rootIconPrefixCls}>
<ConfigProvider prefixCls={rootPrefixCls} iconPrefixCls={rootIconPrefixCls} theme={theme}>
{holder}
</ConfigProvider>
);

2
components/notification/index.zh-CN.md

@ -24,7 +24,6 @@ demo:
<!-- prettier-ignore -->
<code src="./demo/hooks.tsx">Hooks 调用(推荐)</code>
<code src="./demo/basic.tsx">基本</code>
<code src="./demo/duration.tsx">自动关闭的延时</code>
<code src="./demo/with-icon.tsx">带有图标的通知提醒框</code>
<code src="./demo/with-btn.tsx">自定义按钮</code>
@ -32,6 +31,7 @@ demo:
<code src="./demo/placement.tsx">位置</code>
<code src="./demo/custom-style.tsx">自定义样式</code>
<code src="./demo/update.tsx">更新消息内容</code>
<code src="./demo/basic.tsx">静态方法(不推荐)</code>
<code src="./demo/render-panel.tsx" debug>_InternalPanelDoNotUseOrYouWillBeFired</code>
## API

Loading…
Cancel
Save