Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ConfigProvider support config warning level #44809

Merged
merged 4 commits into from Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
40 changes: 34 additions & 6 deletions components/_util/warning.ts
@@ -1,9 +1,15 @@
import * as React from 'react';
import rcWarning, { resetWarned } from 'rc-util/lib/warning';
import rcWarning, { resetWarned as rcResetWarned } from 'rc-util/lib/warning';

export { resetWarned };
export function noop() {}

let deprecatedWarnList: Record<string, string[]> | null = null;

export function resetWarned() {
deprecatedWarnList = null;
rcResetWarned();
}

type Warning = (valid: boolean, component: string, message?: string) => void;

// eslint-disable-next-line import/no-mutable-exports
Expand Down Expand Up @@ -32,7 +38,7 @@ type TypeWarning = (
) => void;

export interface WarningContextProps {
deprecated?: boolean;
strict?: boolean;
}

export const WarningContext = React.createContext<WarningContextProps>({});
Expand All @@ -45,11 +51,33 @@ export const WarningContext = React.createContext<WarningContextProps>({});
export const devUseWarning: () => TypeWarning =
process.env.NODE_ENV !== 'production'
? () => {
const { deprecated } = React.useContext(WarningContext);
const { strict } = React.useContext(WarningContext);

const typeWarning: TypeWarning = (valid, component, type, message) => {
if (deprecated !== false || type !== 'deprecated') {
warning(valid, component, message);
if (!valid) {
if (strict === false && type === 'deprecated') {
const existWarning = deprecatedWarnList;

if (!deprecatedWarnList) {
deprecatedWarnList = {};
}

deprecatedWarnList[component] = deprecatedWarnList[component] || [];
if (!deprecatedWarnList[component].includes(message || '')) {
deprecatedWarnList[component].push(message || '');
}

// Warning for the first time
if (!existWarning) {
// eslint-disable-next-line no-console
console.warn(
'[antd] There exists deprecated usage in your code:',
deprecatedWarnList,
);
}
} else {
warning(valid, component, message);
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion components/avatar/avatar.tsx
Expand Up @@ -139,7 +139,7 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
warning(
!(typeof icon === 'string' && icon.length > 2),
'Avatar',
'deprecated',
'breaking',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
}
Expand Down
14 changes: 14 additions & 0 deletions components/config-provider/__tests__/index.test.tsx
Expand Up @@ -3,6 +3,7 @@ import { SmileOutlined } from '@ant-design/icons';

import type { ConfigConsumerProps, RenderEmptyHandler } from '..';
import ConfigProvider, { ConfigContext } from '..';
import { resetWarned } from '../../_util/warning';
import mountTest from '../../../tests/shared/mountTest';
import { fireEvent, render } from '../../../tests/utils';
import Button from '../../button';
Expand Down Expand Up @@ -124,4 +125,17 @@ describe('ConfigProvider', () => {
expect(rendered).toBeTruthy();
expect(cacheRenderEmpty).toBeFalsy();
});

it('warning support filter level', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {});

render(<ConfigProvider dropdownMatchSelectWidth warning={{ strict: false }} />);
expect(errSpy).not.toHaveBeenCalled();
expect(warnSpy).toHaveBeenCalled();

errSpy.mockRestore();
warnSpy.mockRestore();
});
});
7 changes: 7 additions & 0 deletions components/config-provider/demo/warning.md
@@ -0,0 +1,7 @@
## zh-CN

调整 warning 策略。

## en-US

Adjust warning strategy.
14 changes: 14 additions & 0 deletions components/config-provider/demo/warning.tsx
@@ -0,0 +1,14 @@
import React from 'react';
import { Alert, ConfigProvider, Input, Typography } from 'antd';

const App: React.FC = () => (
<>
<Typography.Title level={4}>Open single page to check the console</Typography.Title>
<ConfigProvider warning={{ strict: false }}>
<Alert closeText="deprecated" />
<Input.Group />
</ConfigProvider>
</>
);

export default App;
4 changes: 3 additions & 1 deletion components/config-provider/index.en-US.md
Expand Up @@ -13,8 +13,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YC4ERpGAddoAAA
This component provides a configuration to all React components underneath itself via the [context API](https://facebook.github.io/react/docs/context.html). In the render tree all components will have access to the provided config.

```tsx
import { ConfigProvider } from 'antd';
import React from 'react';
import { ConfigProvider } from 'antd';

// ...
const Demo: React.FC = () => (
Expand Down Expand Up @@ -46,6 +46,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
<code src="./demo/wave.tsx">Custom Wave</code>
<code src="./demo/prefixCls.tsx" debug>prefixCls</code>
<code src="./demo/useConfig.tsx" debug>useConfig</code>
<code src="./demo/warning.tsx" debug>warning</code>

## API

Expand All @@ -66,6 +67,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
| renderEmpty | Set empty content of components. Ref [Empty](/components/empty/) | function(componentName: string): ReactNode | - | |
| 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 |
| warning | Config warning level, when `strict` is `false`, it will aggregate deprecated information into a single message | { strict: boolean } | - | 5.10.0 |

### ConfigProvider.config()

Expand Down
19 changes: 9 additions & 10 deletions components/config-provider/index.tsx
Expand Up @@ -6,7 +6,7 @@ import useMemo from 'rc-util/lib/hooks/useMemo';
import { merge } from 'rc-util/lib/utils/set';
import type { Options } from 'scroll-into-view-if-needed';

import warning from '../_util/warning';
import warning, { WarningContext, type WarningContextProps } from '../_util/warning';
import type { RequiredMark } from '../form/Form';
import ValidateMessagesContext from '../form/validateMessagesContext';
import type { InputProps } from '../input';
Expand Down Expand Up @@ -146,8 +146,7 @@ export interface ConfigProviderProps {
popupOverflow?: PopupOverflow;
theme?: ThemeConfig;

// TODO: wait for https://github.com/ant-design/ant-design/discussions/44551
// warning?: WarningContextProps;
warning?: WarningContextProps;

alert?: ComponentStyleConfig;
anchor?: ComponentStyleConfig;
Expand Down Expand Up @@ -337,7 +336,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
colorPicker,
datePicker,
wave,
// warning: warningConfig,
warning: warningConfig,
} = props;

// =================================== Context ===================================
Expand Down Expand Up @@ -427,7 +426,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
colorPicker,
datePicker,
wave,
// warning: warningConfig,
warning: warningConfig,
};

const config = {
Expand Down Expand Up @@ -562,11 +561,11 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
}

// ================================== Warning ===================================
// if (memoedConfig.warning) {
// childNode = (
// <WarningContext.Provider value={memoedConfig.warning}>{childNode}</WarningContext.Provider>
// );
// }
if (memoedConfig.warning) {
childNode = (
<WarningContext.Provider value={memoedConfig.warning}>{childNode}</WarningContext.Provider>
);
}

// =================================== Render ===================================
if (componentDisabled !== undefined) {
Expand Down
6 changes: 4 additions & 2 deletions components/config-provider/index.zh-CN.md
Expand Up @@ -14,8 +14,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YC4ERpGAddoAAA
ConfigProvider 使用 React 的 [context](https://facebook.github.io/react/docs/context.html) 特性,只需在应用外围包裹一次即可全局生效。

```tsx
import { ConfigProvider } from 'antd';
import React from 'react';
import { ConfigProvider } from 'antd';

// ...
const Demo: React.FC = () => (
Expand Down Expand Up @@ -46,7 +46,8 @@ export default Demo;
<code src="./demo/theme.tsx">主题</code>
<code src="./demo/wave.tsx">自定义波纹</code>
<code src="./demo/prefixCls.tsx" debug>前缀</code>
<code src="./demo/useConfig.tsx" debug>useConfig</code>
<code src="./demo/useConfig.tsx" debug>获取配置</code>
<code src="./demo/warning.tsx" debug>警告</code>

## API

Expand All @@ -67,6 +68,7 @@ export default Demo;
| renderEmpty | 自定义组件空状态。参考 [空状态](/components/empty-cn) | function(componentName: string): ReactNode | - | |
| theme | 设置主题,参考 [定制主题](/docs/react/customize-theme-cn) | - | - | 5.0.0 |
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 4.3.0 |
| warning | 设置警告等级,`strict` 为 `false` 时会将废弃相关信息聚合为单条信息 | { strict: boolean } | - | 5.10.0 |

### ConfigProvider.config()

Expand Down