refactor: deprecatedWarning (#44791)

* refactor: deprecatedWraning

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code
This commit is contained in:
kiner-tang(文辉) 2023-09-13 22:07:33 +08:00 committed by GitHub
parent 72da2678aa
commit d5abbad8f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 241 additions and 471 deletions

View File

@ -1,3 +1,7 @@
import { render } from '@testing-library/react';
import React from 'react';
import { devUseWarning as useWarning } from '../warning';
describe('Test warning', () => {
let spy: jest.SpyInstance;
@ -40,13 +44,40 @@ describe('Test warning', () => {
expect(spy).not.toHaveBeenCalled();
});
it('should show warning when using devUseWarning', async () => {
const App = () => {
// Don't use dynamic import to fixed issue: TypeError: Cannot read properties of null (reading 'useContext')
const warning = useWarning('Test');
warning(false, 'usage', 'test message');
warning.deprecated(false, 'old prop', 'new prop');
return null;
};
render(<App />);
expect(spy).toHaveBeenCalledWith('Warning: [antd: Test] test message');
expect(spy).toHaveBeenCalledWith(
'Warning: [antd: Test] `old prop` is deprecated. Please use `new prop` instead.',
);
expect(spy).toHaveBeenCalledTimes(2);
});
});
describe('process.env.NODE_ENV === "production"', () => {
it('Whether `true` or `false`, do not exec `console.error`', async () => {
const prevEnv = process.env.NODE_ENV;
let prevEnv: string | undefined;
const mockNodeEnv = () => {
prevEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'production';
};
const restoreNodeEnv = () => {
process.env.NODE_ENV = prevEnv;
};
beforeEach(() => {
mockNodeEnv();
});
afterEach(() => {
restoreNodeEnv();
});
it('Whether `true` or `false`, do not exec `console.error`', async () => {
const { default: warning, noop } = await import('../warning');
expect(warning).toEqual(noop);
@ -56,8 +87,19 @@ describe('Test warning', () => {
warning(true, 'error message');
expect(spy).not.toHaveBeenCalled();
});
process.env.NODE_ENV = prevEnv;
it('should not show warning when using devUseWarning', async () => {
const { devUseWarning } = await import('../warning');
const App = () => {
const warning = devUseWarning('Test');
warning(false, 'usage', 'test message');
warning.deprecated(false, 'old prop', 'new prop');
return null;
};
render(<App />);
expect(spy).toHaveBeenCalledTimes(0);
});
});
});

View File

@ -19,9 +19,8 @@ if (process.env.NODE_ENV !== 'production') {
};
}
type TypeWarning = (
type BaseTypeWarning = (
valid: boolean,
component: string,
/**
* - deprecated: Some API will be removed in future but still support now.
* - usage: Some API usage is not correct.
@ -31,6 +30,10 @@ type TypeWarning = (
message?: string,
) => void;
type TypeWarning = BaseTypeWarning & {
deprecated: (valid: boolean, oldProp: string, newProp: string, message?: string) => void;
};
export interface WarningContextProps {
deprecated?: boolean;
}
@ -42,19 +45,35 @@ export const WarningContext = React.createContext<WarningContextProps>({});
* since this is only used in development.
* We should always wrap this in `if (process.env.NODE_ENV !== 'production')` condition
*/
export const devUseWarning: () => TypeWarning =
export const devUseWarning: (component: string) => TypeWarning =
process.env.NODE_ENV !== 'production'
? () => {
? (component: string) => {
const { deprecated } = React.useContext(WarningContext);
const typeWarning: TypeWarning = (valid, component, type, message) => {
const typeWarning: TypeWarning = (valid, type, message) => {
if (deprecated !== false || type !== 'deprecated') {
warning(valid, component, message);
}
};
typeWarning.deprecated = (valid, oldProp, newProp, message) => {
typeWarning(
valid,
'deprecated',
`\`${oldProp}\` is deprecated. Please use \`${newProp}\` instead.${
message ? ` ${message}` : ''
}`,
);
};
return typeWarning;
}
: () => noop;
: () => {
const noopWarning: TypeWarning = () => {};
noopWarning.deprecated = noop;
return noopWarning;
};
export default warning;

View File

@ -120,15 +120,10 @@ const Alert: React.FC<AlertProps> = (props) => {
const [closed, setClosed] = React.useState(false);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
warning(
!closeText,
'Alert',
'deprecated',
'`closeText` is deprecated. Please use `closeIcon` instead.',
);
const warning = devUseWarning('Alert');
warning.deprecated(!closeText, 'closeText', 'closeIcon');
}
const ref = React.useRef<HTMLDivElement>(null);
const { getPrefixCls, direction, alert } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('alert', customizePrefixCls);

View File

@ -132,18 +132,12 @@ const AnchorContent: React.FC<InternalAnchorProps> = (props) => {
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Anchor');
warning(
!children,
'Anchor',
'deprecated',
'`Anchor children` is deprecated. Please use `items` instead.',
);
warning.deprecated(!children, 'Anchor children', 'items');
warning(
!(anchorDirection === 'horizontal' && items?.some((n) => 'children' in n)),
'Anchor',
'usage',
'`Anchor items#children` is not supported when `Anchor` direction is horizontal.',
);

View File

@ -52,11 +52,10 @@ const AnchorLink: React.FC<AnchorLinkProps> = (props) => {
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Anchor.Link');
warning(
!children || direction !== 'horizontal',
'Anchor.Link',
'usage',
'`Anchor.Link children` is not supported when `Anchor` direction is horizontal',
);

View File

@ -1887,7 +1887,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
exports[`renders components/auto-complete/demo/form-debug.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input.Group] 'Input.Group' is deprecated. Please use 'Space.Compact' instead.",
"Warning: [antd: Input.Group] \`Input.Group\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;

View File

@ -110,7 +110,7 @@ describe('AutoComplete', () => {
/>,
);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: AutoComplete] `dropdownClassName` is deprecated, please use `popupClassName` instead.',
'Warning: [antd: AutoComplete] `dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
expect(container.querySelector('.legacy')).toBeTruthy();

View File

@ -111,28 +111,17 @@ const AutoComplete: React.ForwardRefRenderFunction<RefSelectProps, AutoCompleteP
}
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('AutoComplete');
warning(
!('dataSource' in props),
'AutoComplete',
'deprecated',
'`dataSource` is deprecated, please use `options` instead.',
);
warning.deprecated(!('dataSource' in props), 'dataSource', 'options');
warning(
!customizeInput || !('size' in props),
'AutoComplete',
'usage',
'You need to control style self instead of setting `size` when using customize input.',
);
warning(
!dropdownClassName,
'AutoComplete',
'deprecated',
'`dropdownClassName` is deprecated, please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
}
const { getPrefixCls } = React.useContext<ConfigConsumerProps>(ConfigContext);

View File

@ -134,11 +134,10 @@ const InternalAvatar: React.ForwardRefRenderFunction<HTMLSpanElement, AvatarProp
}, [screens, size]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Avatar');
warning(
!(typeof icon === 'string' && icon.length > 2),
'Avatar',
'deprecated',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);

View File

@ -17,7 +17,7 @@ Array [
exports[`renders components/back-top/demo/basic.tsx extend context correctly 2`] = `
[
"Warning: [antd: BackTop] \`BackTop\` is deprecated, please use \`FloatButton.BackTop\` instead.",
"Warning: [antd: BackTop] \`BackTop\` is deprecated. Please use \`FloatButton.BackTop\` instead.",
]
`;
@ -54,6 +54,6 @@ exports[`renders components/back-top/demo/custom.tsx extend context correctly 1`
exports[`renders components/back-top/demo/custom.tsx extend context correctly 2`] = `
[
"Warning: [antd: BackTop] \`BackTop\` is deprecated, please use \`FloatButton.BackTop\` instead.",
"Warning: [antd: BackTop] \`BackTop\` is deprecated. Please use \`FloatButton.BackTop\` instead.",
]
`;

View File

@ -47,7 +47,7 @@ describe('BackTop', () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(<BackTop />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: BackTop] `BackTop` is deprecated, please use `FloatButton.BackTop` instead.',
'Warning: [antd: BackTop] `BackTop` is deprecated. Please use `FloatButton.BackTop` instead.',
);
errSpy.mockRestore();
});

View File

@ -50,14 +50,9 @@ const BackTop: React.FC<BackTopProps> = (props) => {
);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('BackTop');
warning(
false,
'BackTop',
'deprecated',
'`BackTop` is deprecated, please use `FloatButton.BackTop` instead.',
);
warning.deprecated(false, 'BackTop', 'FloatButton.BackTop');
}
React.useEffect(() => {

View File

@ -99,24 +99,17 @@ const Breadcrumb = <T extends AnyObject = AnyObject>(props: BreadcrumbProps<T>)
const mergedItems = useItems(items, legacyRoutes);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
warning(
!legacyRoutes,
'Breadcrumb',
'deprecated',
'`routes` is deprecated. Please use `items` instead.',
);
const warning = devUseWarning('Breadcrumb');
warning.deprecated(!legacyRoutes, 'routes', 'items');
// Deprecated warning for breadcrumb children
if (!mergedItems || mergedItems.length === 0) {
const childList = toArray(children);
warning(
warning.deprecated(
childList.length === 0,
'Breadcrumb',
'deprecated',
'`Breadcrumb.Item and Breadcrumb.Separator` is deprecated. Please use `items` instead.',
'Breadcrumb.Item and Breadcrumb.Separator',
'items',
);
childList.forEach((element: any) => {
@ -125,7 +118,6 @@ const Breadcrumb = <T extends AnyObject = AnyObject>(props: BreadcrumbProps<T>)
element.type &&
(element.type.__ANT_BREADCRUMB_ITEM === true ||
element.type.__ANT_BREADCRUMB_SEPARATOR === true),
'Breadcrumb',
'usage',
"Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children",
);

View File

@ -1,12 +1,12 @@
import DownOutlined from '@ant-design/icons/DownOutlined';
import * as React from 'react';
import { devUseWarning } from '../_util/warning';
import { ConfigContext } from '../config-provider';
import type { DropdownProps } from '../dropdown/dropdown';
import Dropdown from '../dropdown/dropdown';
import type { ItemType } from './Breadcrumb';
import BreadcrumbSeparator from './BreadcrumbSeparator';
import { renderItem } from './useItemRender';
import { devUseWarning } from '../_util/warning';
export interface SeparatorType {
separator?: React.ReactNode;
@ -42,14 +42,9 @@ export const InternalBreadcrumbItem: React.FC<BreadcrumbItemProps> = (props) =>
// Warning for deprecated usage
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Breadcrumb.Item');
warning(
!('overlay' in props),
'Breadcrumb.Item',
'deprecated',
'`overlay` is deprecated. Please use `menu` instead.',
);
warning.deprecated(!('overlay' in props), 'overlay', 'menu');
}
/** If overlay is have Wrap a Dropdown */

View File

@ -39,14 +39,9 @@ const ButtonGroup: React.FC<ButtonGroupProps> = (props) => {
}
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Button.Group');
warning(
!size || ['large', 'small', 'middle'].includes(size),
'Button.Group',
'usage',
'Invalid prop `size`.',
);
warning(!size || ['large', 'small', 'middle'].includes(size), 'usage', 'Invalid prop `size`.');
}
const classes = classNames(

View File

@ -184,18 +184,16 @@ const InternalButton: React.ForwardRefRenderFunction<
};
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Button');
warning(
!(typeof icon === 'string' && icon.length > 2),
'Button',
'breaking',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
warning(
!(ghost && isUnBorderedButtonType(type)),
'Button',
'usage',
"`link` or `text` button can't be a `ghost` button.",
);

View File

@ -125,32 +125,12 @@ function generateCalendar<DateType>(generateConfig: GenerateConfig<DateType>) {
// ====================== Warning =======================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Calendar');
warning(
!dateFullCellRender,
'Calendar',
'deprecated',
'`dateFullCellRender` is deprecated. Please use `fullCellRender` instead.',
);
warning(
!dateCellRender,
'Calendar',
'deprecated',
'`dateCellRender` is deprecated. Please use `cellRender` instead.',
);
warning(
!monthFullCellRender,
'Calendar',
'deprecated',
'`monthFullCellRender` is deprecated. Please use `fullCellRender` instead.',
);
warning(
!monthCellRender,
'Calendar',
'deprecated',
'`monthCellRender` is deprecated. Please use `cellRender` instead.',
);
warning.deprecated(!dateFullCellRender, 'dateFullCellRender', 'fullCellRender');
warning.deprecated(!dateCellRender, 'dateCellRender', 'cellRender');
warning.deprecated(!monthFullCellRender, 'monthFullCellRender', 'fullCellRender');
warning.deprecated(!monthCellRender, 'monthCellRender', 'cellRender');
}
// ====================== State =======================

View File

@ -194,18 +194,12 @@ const Cascader = React.forwardRef<CascaderRef, CascaderProps<any>>((props, ref)
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Cascader');
warning(
!dropdownClassName,
'Cascader',
'deprecated',
'`dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
warning(
!('showArrow' in props),
'Cascader',
'deprecated',
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.',
);

View File

@ -78,11 +78,10 @@ const InternalCheckbox: React.ForwardRefRenderFunction<CheckboxRef, CheckboxProp
const prevValue = React.useRef(restProps.value);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Checkbox');
warning(
'checked' in restProps || !!checkboxGroup || !('value' in restProps),
'Checkbox',
'usage',
'`value` is not a valid prop, do you mean `checked`?',
);

View File

@ -79,12 +79,11 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
const [wrapSSR, hashId] = useStyle(prefixCls);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Collapse');
// Warning if use legacy type `expandIconPosition`
warning(
expandIconPosition !== 'left' && expandIconPosition !== 'right',
'Collapse',
'deprecated',
'`expandIconPosition` with `left` or `right` is deprecated. Please use `start` or `end` instead.',
);

View File

@ -25,14 +25,9 @@ export interface CollapsePanelProps {
const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((props, ref) => {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Collapse.Panel');
warning(
!('disabled' in props),
'Collapse.Panel',
'deprecated',
'`disabled` is deprecated. Please use `collapsible="disabled"` instead.',
);
warning.deprecated(!('disabled' in props), 'disabled', 'collapsible="disabled"');
}
const { getPrefixCls } = React.useContext(ConfigContext);

View File

@ -151,11 +151,10 @@ const ColorPicker: CompoundedComponent = (props) => {
// ===================== Warning ======================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('ColorPicker');
warning(
!(disabledAlpha && isAlphaColor),
'ColorPicker',
'usage',
'`disabledAlpha` will make the alpha to be 100% when use alpha color.',
);

View File

@ -11,13 +11,12 @@ export interface PropWarningProps {
* This will be empty function in production.
*/
const PropWarning = React.memo(({ dropdownMatchSelectWidth }: PropWarningProps) => {
const warning = devUseWarning();
const warning = devUseWarning('ConfigProvider');
warning(
warning.deprecated(
dropdownMatchSelectWidth === undefined,
'ConfigProvider',
'deprecated',
'`dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
'dropdownMatchSelectWidth',
'popupMatchSelectWidth',
);
return null;

View File

@ -78,14 +78,9 @@ export default function generateRangePicker<DateType>(generateConfig: GenerateCo
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('DatePicker.RangePicker');
warning(
!dropdownClassName,
'DatePicker.RangePicker',
'deprecated',
'`dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
}
// ===================== Size =====================

View File

@ -106,21 +106,15 @@ export default function generatePicker<DateType>(generateConfig: GenerateConfig<
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning(displayName! || 'DatePicker');
warning(
picker !== 'quarter',
displayName!,
'deprecated',
`DatePicker.${displayName} is legacy usage. Please use DatePicker[picker='${picker}'] directly.`,
);
warning(
!dropdownClassName,
displayName || 'DatePicker',
'deprecated',
'`dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
}
// ===================== Size =====================

View File

@ -69,14 +69,9 @@ const useRow = (mergedColumn: number, items: InternalDescriptionsItemType[]) =>
const [rows, exceed] = useMemo(() => getCalcRows(items, mergedColumn), [items, mergedColumn]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Descriptions');
warning(
!exceed,
'Descriptions',
'usage',
'Sum of column `span` in a line not match `column` of Descriptions.',
);
warning(!exceed, 'usage', 'Sum of column `span` in a line not match `column` of Descriptions.');
}
return rows;

View File

@ -76,11 +76,10 @@ const Divider: React.FC<DividerProps> = (props) => {
// Warning children not work in vertical mode
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Divider');
warning(
!children || type !== 'vertical',
'Divider',
'usage',
'`children` not working in `vertical` mode.',
);

View File

@ -135,10 +135,10 @@ describe('Drawer', () => {
expect(afterVisibleChange).toHaveBeenCalledTimes(1);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Drawer] `visible` is deprecated, please use `open` instead.',
'Warning: [antd: Drawer] `visible` is deprecated. Please use `open` instead.',
);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Drawer] `afterVisibleChange` is deprecated, please use `afterOpenChange` instead.',
'Warning: [antd: Drawer] `afterVisibleChange` is deprecated. Please use `afterOpenChange` instead.',
);
errorSpy.mockRestore();

View File

@ -88,24 +88,18 @@ const Drawer: React.FC<DrawerProps> & {
// ========================== Warning ===========================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Drawer');
[
['visible', 'open'],
['afterVisibleChange', 'afterOpenChange'],
].forEach(([deprecatedName, newName]) => {
warning(
!(deprecatedName in props),
'Drawer',
'deprecated',
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
);
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
});
if (getContainer !== undefined && props.style?.position === 'absolute') {
warning(
false,
'Drawer',
'breaking',
'`style` is replaced by `rootStyle` in v5. Please check that `position: absolute` is necessary.',
);

View File

@ -8454,8 +8454,7 @@ exports[`renders components/dropdown/demo/render-panel.tsx extend context correc
exports[`renders components/dropdown/demo/render-panel.tsx extend context correctly 2`] = `
[
"Warning: [antd: Dropdown] \`visible\` is deprecated which will be removed in next major version, please use \`open\` instead.",
"Warning: [antd: Dropdown] \`visible\` is deprecated, please use \`open\` instead.",
"Warning: [antd: Dropdown] \`visible\` is deprecated. Please use \`open\` instead.",
]
`;

View File

@ -231,10 +231,10 @@ describe('Dropdown', () => {
expect(document.querySelector('.bamboo')).toBeTruthy();
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Dropdown] `visible` is deprecated, please use `open` instead.',
'Warning: [antd: Dropdown] `visible` is deprecated. Please use `open` instead.',
);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Dropdown] `onVisibleChange` is deprecated, please use `onOpenChange` instead.',
'Warning: [antd: Dropdown] `onVisibleChange` is deprecated. Please use `onOpenChange` instead.',
);
fireEvent.click(container.querySelector('.little')!);

View File

@ -109,27 +109,17 @@ const Dropdown: CompoundedComponent = (props) => {
} = React.useContext(ConfigContext);
// Warning for deprecated usage
const warning = devUseWarning();
const warning = devUseWarning('Dropdown');
if (process.env.NODE_ENV !== 'production') {
[
['visible', 'open'],
['onVisibleChange', 'onOpenChange'],
].forEach(([deprecatedName, newName]) => {
warning(
!(deprecatedName in props),
'Dropdown',
'deprecated',
`\`${deprecatedName}\` is deprecated which will be removed in next major version, please use \`${newName}\` instead.`,
);
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
});
warning(
!('overlay' in props),
'Dropdown',
'deprecated',
'`overlay` is deprecated. Please use `menu` instead.',
);
warning.deprecated(!('overlay' in props), 'overlay', 'menu');
}
const memoTransitionName = React.useMemo<string>(() => {
@ -161,7 +151,6 @@ const Dropdown: CompoundedComponent = (props) => {
const newPlacement = placement.slice(0, placement.indexOf('Center')) as DropdownPlacement;
warning(
!placement.includes('Center'),
'Dropdown',
'deprecated',
`You are using '${placement}' placement in Dropdown, which is deprecated. Try to use '${newPlacement}' instead.`,
);
@ -171,12 +160,7 @@ const Dropdown: CompoundedComponent = (props) => {
['visible', 'open'],
['onVisibleChange', 'onOpenChange'],
].forEach(([deprecatedName, newName]) => {
warning(
!(deprecatedName in props),
'Dropdown',
'deprecated',
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
);
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
});
}
@ -266,7 +250,6 @@ const Dropdown: CompoundedComponent = (props) => {
// Warning if use other mode
warning(
!mode || mode === 'vertical',
'Dropdown',
'usage',
`mode="${mode}" is not supported for Dropdown's Menu.`,
);

View File

@ -85,11 +85,10 @@ const FloatButton: React.ForwardRefRenderFunction<
}
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('FloatButton');
warning(
!(shape === 'circle' && description),
'FloatButton',
'usage',
'supported only when `shape` is `square`. Due to narrow space for text, short sentence is recommended.',
);

View File

@ -94,11 +94,10 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('FloatButton.Group');
warning(
!('open' in props) || !!trigger,
'FloatButton.Group',
'usage',
'`open` need to be used together with `trigger`',
);

View File

@ -129,10 +129,10 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
const [wrapSSR, hashId] = useStyle(prefixCls);
// ========================= Warn =========================
const warning = devUseWarning();
const warning = devUseWarning('Form.Item');
if (process.env.NODE_ENV !== 'production') {
warning(name !== null, 'Form.Item', 'usage', '`null` is passed as `name` property');
warning(name !== null, 'usage', '`null` is passed as `name` property');
}
// ========================= MISC =========================
@ -307,14 +307,12 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
warning(
!(shouldUpdate && dependencies),
'Form.Item',
'usage',
"`shouldUpdate` and `dependencies` shouldn't be used together. See https://u.ant.design/form-deps.",
);
if (Array.isArray(mergedChildren) && hasName) {
warning(
false,
'Form.Item',
'usage',
'A `Form.Item` with a `name` prop must have a single child element. For information on how to render more complex form items, see https://u.ant.design/complex-form-item.',
);
@ -322,27 +320,23 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
} else if (isRenderProps && (!(shouldUpdate || dependencies) || hasName)) {
warning(
!!(shouldUpdate || dependencies),
'Form.Item',
'usage',
'A `Form.Item` with a render function must have either `shouldUpdate` or `dependencies`.',
);
warning(
!hasName,
'Form.Item',
'usage',
'A `Form.Item` with a render function cannot be a field, and thus cannot have a `name` prop.',
);
} else if (dependencies && !isRenderProps && !hasName) {
warning(
false,
'Form.Item',
'usage',
'Must set `name` or use a render function when `dependencies` is set.',
);
} else if (isValidElement(mergedChildren)) {
warning(
mergedChildren.props.defaultValue === undefined,
'Form.Item',
'usage',
'`defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.',
);
@ -409,7 +403,6 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
} else {
warning(
!mergedName.length,
'Form.Item',
'usage',
'`name` is only used for validate React element. If you are using Form.Item as layout display, please remove `name` instead.',
);

View File

@ -37,12 +37,11 @@ const FormList: React.FC<FormListProps> = ({
...props
}) => {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Form.List');
warning(
typeof props.name === 'number' ||
(Array.isArray(props.name) ? !!props.name.length : !!props.name),
'Form.List',
'usage',
'Miss `name` prop.',
);

View File

@ -14,11 +14,10 @@ const useFormItemStatus: UseFormItemStatus = () => {
const { status, errors = [], warnings = [] } = useContext(FormItemInputContext);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Form.Item');
warning(
status !== undefined,
'Form.Item',
'usage',
'Form.Item.useStatus should be used under Form.Item component. For more information: https://u.ant.design/form-item-usestatus',
);

View File

@ -6,13 +6,13 @@ import type { FormProps } from '../Form';
const names: Record<string, number> = {};
export default function useFormWarning({ name }: FormProps) {
const warning = devUseWarning();
const warning = devUseWarning('Form');
useEffect(() => {
if (name) {
names[name] = (names[name] || 0) + 1;
warning(names[name] <= 1, 'Form', 'usage', 'There exist multiple Form with same `name`.');
warning(names[name] <= 1, 'usage', 'There exist multiple Form with same `name`.');
return () => {
names[name] -= 1;

View File

@ -2,9 +2,9 @@ import { devUseWarning } from '../_util/warning';
const Icon: React.FC = () => {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Icon');
warning(false, 'Icon', 'usage', 'Empty Icon');
warning(false, 'usage', 'Empty Icon');
}
return null;
};

View File

@ -50,14 +50,9 @@ const Group: React.FC<GroupProps> = (props) => {
);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Input.Group');
warning(
false,
'Input.Group',
'deprecated',
`'Input.Group' is deprecated. Please use 'Space.Compact' instead.`,
);
warning.deprecated(false, 'Input.Group', 'Space.Compact');
}
return wrapSSR(

View File

@ -116,13 +116,12 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
/* eslint-disable react-hooks/rules-of-hooks */
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Input');
useEffect(() => {
if (inputHasPrefixSuffix && !prevHasPrefixSuffix.current) {
warning(
document.activeElement === inputRef.current?.input,
'Input',
'usage',
`When Input is focused, dynamic add or remove prefix / suffix will make it lose focus caused by dom structure change. Read more: https://ant.design/components/input/#FAQ`,
);

View File

@ -9255,7 +9255,7 @@ exports[`renders components/input/demo/group.tsx extend context correctly 1`] =
exports[`renders components/input/demo/group.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input.Group] 'Input.Group' is deprecated. Please use 'Space.Compact' instead.",
"Warning: [antd: Input.Group] \`Input.Group\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;

View File

@ -124,7 +124,7 @@ describe('Input', () => {
render(<Input.Group />);
expect(errorSpy).toHaveBeenCalledWith(
"Warning: [antd: Input.Group] 'Input.Group' is deprecated. Please use 'Space.Compact' instead.",
'Warning: [antd: Input.Group] `Input.Group` is deprecated. Please use `Space.Compact` instead.',
);
});
});

View File

@ -69,11 +69,10 @@ const LocaleProvider: React.FC<LocaleProviderProps> = (props) => {
const { locale = {} as Locale, children, _ANT_MARK__ } = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('LocaleProvider');
warning(
_ANT_MARK__ === ANT_MARK,
'LocaleProvider',
'deprecated',
'`LocaleProvider` is deprecated. Please use `locale` with `ConfigProvider` instead: http://u.ant.design/locale',
);

View File

@ -88,14 +88,9 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Mentions');
warning(
!children,
'Mentions',
'deprecated',
'`Mentions.Option` is deprecated. Please use `options` instead.',
);
warning.deprecated(!children, 'Mentions.Option', 'options');
}
const {

View File

@ -72,28 +72,21 @@ const InternalMenu = forwardRef<RcMenuRef, InternalMenuProps>((props, ref) => {
// ======================== Warning ==========================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Menu');
warning(
!('inlineCollapsed' in props && mode !== 'inline'),
'Menu',
'usage',
'`inlineCollapsed` should only be used when `mode` is inline.',
);
warning(
!(props.siderCollapsed !== undefined && 'inlineCollapsed' in props),
'Menu',
'usage',
'`inlineCollapsed` not control Menu under Sider. Should set `collapsed` on Sider instead.',
);
warning(
'items' in props && !children,
'Menu',
'deprecated',
'`children` will be removed in next major version. Please use `items` instead.',
);
warning.deprecated('items' in props && !children, 'children', 'items');
}
overrideObj.validator?.({ mode });

View File

@ -123,7 +123,7 @@ export function useInternalMessage(
): readonly [MessageInstance, React.ReactElement] {
const holderRef = React.useRef<HolderRef>(null);
const warning = devUseWarning();
const warning = devUseWarning('Message');
// ================================ API ================================
const wrapAPI = React.useMemo<MessageInstance>(() => {
@ -139,7 +139,6 @@ export function useInternalMessage(
if (!holderRef.current) {
warning(
false,
'Message',
'usage',
'You are calling notice in render which will break in React 18 concurrent mode. Please trigger in effect instead.',
);

View File

@ -62,11 +62,10 @@ export function ConfirmContent(
} = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Modal');
warning(
!(typeof icon === 'string' && icon.length > 2),
'Modal',
'breaking',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);
@ -190,14 +189,9 @@ const ConfirmDialog: React.FC<ConfirmDialogProps> = (props) => {
} = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Modal');
warning(
visible === undefined,
'Modal',
'deprecated',
`\`visible\` is deprecated, please use \`open\` instead.`,
);
warning.deprecated(visible === undefined, 'visible', 'open');
}
const confirmPrefixCls = `${prefixCls}-confirm`;

View File

@ -55,14 +55,9 @@ const Modal: React.FC<ModalProps> = (props) => {
};
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Modal');
warning(
!('visible' in props),
'Modal',
'deprecated',
`\`visible\` will be removed in next major version, please use \`open\` instead.`,
);
warning.deprecated(!('visible' in props), 'visible', 'open');
}
const {

View File

@ -117,7 +117,7 @@ describe('Modal', () => {
render(<Modal visible />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Modal] `visible` will be removed in next major version, please use `open` instead.',
'Warning: [antd: Modal] `visible` is deprecated. Please use `open` instead.',
);
expect(document.querySelector('.ant-modal')).toBeTruthy();

View File

@ -110,7 +110,7 @@ export function useInternalNotification(
): readonly [NotificationInstance, React.ReactElement] {
const holderRef = React.useRef<HolderRef>(null);
const warning = devUseWarning();
const warning = devUseWarning('Notification');
// ================================ API ================================
const wrapAPI = React.useMemo<NotificationInstance>(() => {
@ -121,7 +121,6 @@ export function useInternalNotification(
if (!holderRef.current) {
warning(
false,
'Notification',
'usage',
'You are calling notice in render which will break in React 18 concurrent mode. Please trigger in effect instead.',
);

View File

@ -726,7 +726,7 @@ exports[`renders components/popover/demo/arrow-point-at-center.tsx extend contex
exports[`renders components/popover/demo/arrow-point-at-center.tsx extend context correctly 2`] = `
[
"Warning: [antd: Tooltip] \`arrowPointAtCenter\` is deprecated, please use \`arrow={{ pointAtCenter: true }}\` instead.",
"Warning: [antd: Tooltip] \`arrowPointAtCenter\` is deprecated. Please use \`arrow={{ pointAtCenter: true }}\` instead.",
]
`;

View File

@ -99,14 +99,9 @@ const Line: React.FC<LineProps> = (props) => {
const [width, height] = getSize(mergedSize, 'line', { strokeWidth });
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Progress');
warning(
!('strokeWidth' in props),
'Progress',
'deprecated',
'`strokeWidth` is deprecated. Please use `size` instead.',
);
warning.deprecated(!('strokeWidth' in props), 'strokeWidth', 'size');
}
const percentStyle: React.CSSProperties = {

View File

@ -123,37 +123,21 @@ const Progress = React.forwardRef<HTMLDivElement, ProgressProps>((props, ref) =>
}, [showInfo, percent, percentNumber, progressStatus, type, prefixCls, format]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Progress');
warning(
!('successPercent' in props),
'Progress',
'deprecated',
'`successPercent` is deprecated. Please use `success.percent` instead.',
);
warning(
!('width' in props),
'Progress',
'deprecated',
'`width` is deprecated. Please use `size` instead.',
);
warning.deprecated(!('successPercent' in props), 'successPercent', 'success.percent');
warning.deprecated(!('width' in props), 'width', 'size');
if ((type === 'circle' || type === 'dashboard') && Array.isArray(size)) {
warning(
false,
'Progress',
'usage',
'Type "circle" and "dashboard" do not accept array as `size`, please use number or preset size instead.',
);
}
if (props.success && 'progress' in props.success) {
warning(
false,
'Progress',
'deprecated',
'`success.progress` is deprecated. Please use `success.percent` instead.',
);
warning.deprecated(false, 'success.progress', 'success.percent');
}
}

View File

@ -57,13 +57,12 @@ const QRCode: React.FC<QRCodeProps> = (props) => {
const [locale] = useLocale('QRCode');
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('QRCode');
warning(!!value, 'QRCode', 'usage', 'need to receive `value` props');
warning(!!value, 'usage', 'need to receive `value` props');
warning(
!(icon && errorLevel === 'L'),
'QRCode',
'usage',
'ErrorLevel `L` is not recommended to be used with `icon`, for scanning result would be affected by low level.',
);

View File

@ -23,14 +23,9 @@ const InternalRadio: React.ForwardRefRenderFunction<RadioRef, RadioProps> = (pro
const { isFormItemInput } = React.useContext(FormItemInputContext);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Radio');
warning(
!('optionType' in props),
'Radio',
'usage',
'`optionType` is only support in Radio.Group.',
);
warning(!('optionType' in props), 'usage', '`optionType` is only support in Radio.Group.');
}
const onChange = (e: RadioChangeEvent) => {

View File

@ -61,11 +61,10 @@ const Icon: React.FC<IconProps> = ({ prefixCls, icon, status }) => {
const className = classNames(`${prefixCls}-icon`);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Result');
warning(
!(typeof icon === 'string' && icon.length > 2),
'Result',
'breaking',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);

View File

@ -223,25 +223,18 @@ const InternalSelect = <
// ====================== Warning ======================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Select');
warning(
!dropdownClassName,
'Select',
'deprecated',
'`dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
warning(
warning.deprecated(
dropdownMatchSelectWidth === undefined,
'Select',
'deprecated',
'`dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
'dropdownMatchSelectWidth',
'popupMatchSelectWidth',
);
warning(
!('showArrow' in props),
'Select',
'deprecated',
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.',
);

View File

@ -39,14 +39,9 @@ export default function useIcons({
componentName: string;
}) {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning(componentName);
warning(
!clearIcon,
componentName,
'deprecated',
'`clearIcon` is deprecated, please use `allowClear={{ clearIcon: React.ReactNode }}` instead.',
);
warning.deprecated(!clearIcon, 'clearIcon', 'allowClear={{ clearIcon: React.ReactNode }}');
}
// Clear Icon

View File

@ -171,27 +171,27 @@ describe('Slider', () => {
const { container, rerender } = render(<TSSlider tooltipPrefixCls="xxx" />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Slider] `tooltipPrefixCls` is deprecated, please use `tooltip.prefixCls` instead.',
'Warning: [antd: Slider] `tooltipPrefixCls` is deprecated. Please use `tooltip.prefixCls` instead.',
);
rerender(<TSSlider getTooltipPopupContainer={() => document.body} />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Slider] `getTooltipPopupContainer` is deprecated, please use `tooltip.getPopupContainer` instead.',
'Warning: [antd: Slider] `getTooltipPopupContainer` is deprecated. Please use `tooltip.getPopupContainer` instead.',
);
rerender(<TSSlider tipFormatter={(v: any) => v} />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Slider] `tipFormatter` is deprecated, please use `tooltip.formatter` instead.',
'Warning: [antd: Slider] `tipFormatter` is deprecated. Please use `tooltip.formatter` instead.',
);
rerender(<TSSlider tooltipVisible />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Slider] `tooltipVisible` is deprecated, please use `tooltip.open` instead.',
'Warning: [antd: Slider] `tooltipVisible` is deprecated. Please use `tooltip.open` instead.',
);
rerender(<TSSlider tooltipPlacement="left" />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Slider] `tooltipPlacement` is deprecated, please use `tooltip.placement` instead.',
'Warning: [antd: Slider] `tooltipPlacement` is deprecated. Please use `tooltip.placement` instead.',
);
// All should work

View File

@ -166,7 +166,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
// Warning for deprecated usage
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Slider');
[
['tooltipPrefixCls', 'prefixCls'],
@ -175,12 +175,7 @@ const Slider = React.forwardRef<SliderRef, SliderSingleProps | SliderRangeProps>
['tooltipPlacement', 'placement'],
['tooltipVisible', 'open'],
].forEach(([deprecatedName, newName]) => {
warning(
!(deprecatedName in props),
'Slider',
'deprecated',
`\`${deprecatedName}\` is deprecated, please use \`tooltip.${newName}\` instead.`,
);
warning.deprecated(!(deprecatedName in props), deprecatedName, `tooltip.${newName}`);
});
}

View File

@ -111,9 +111,9 @@ const Spin: React.FC<SpinClassProps> = (props) => {
const isNestedPattern = React.useMemo<boolean>(() => typeof children !== 'undefined', [children]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Spin');
warning(!tip || isNestedPattern, 'Spin', 'usage', '`tip` only work in nest pattern.');
warning(!tip || isNestedPattern, 'usage', '`tip` only work in nest pattern.');
}
const { direction, spin } = React.useContext<ConfigConsumerProps>(ConfigContext);

View File

@ -103,7 +103,7 @@ describe('Steps', () => {
expect(container.querySelectorAll('.ant-steps-item')).toHaveLength(1);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Steps] Step is deprecated. Please use `items` directly.',
'Warning: [antd: Menu] `Step` is deprecated. Please use `items` instead.',
);
errorSpy.mockRestore();
});

View File

@ -10,8 +10,8 @@ function filter<T>(items: (T | null)[]): T[] {
export default function useLegacyItems(items?: StepProps[], children?: React.ReactNode) {
if (process.env.NODE_ENV === 'test') {
const warning = devUseWarning();
warning(!children, 'Steps', 'deprecated', 'Step is deprecated. Please use `items` directly.');
const warning = devUseWarning('Menu');
warning.deprecated(!children, 'Step', 'items');
}
if (items) {

View File

@ -57,11 +57,10 @@ const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>((props, ref) =>
} = props;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Switch');
warning(
'checked' in props || !('value' in props),
'Switch',
'usage',
'`value` is not a valid prop, do you mean `checked`?',
);

View File

@ -149,12 +149,11 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
virtual,
} = props;
const warning = devUseWarning();
const warning = devUseWarning('Table');
if (process.env.NODE_ENV !== 'production') {
warning(
!(typeof rowKey === 'function' && rowKey.length > 1),
'Table',
'usage',
'`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.',
);
@ -385,14 +384,13 @@ const InternalTable = <RecordType extends AnyObject = AnyObject>(
}
const { current = 1, total, pageSize = DEFAULT_PAGE_SIZE } = mergedPagination;
warning(current > 0, 'Table', 'usage', '`current` should be positive number.');
warning(current > 0, 'usage', '`current` should be positive number.');
// Dynamic table data
if (mergedData.length < total!) {
if (mergedData.length > pageSize) {
warning(
false,
'Table',
'usage',
'`dataSource` length is less than `pagination.total` but large than `pagination.pageSize`. Please make sure your config correct data with async mode.',
);

View File

@ -174,7 +174,7 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
};
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Table');
[
['filterDropdownVisible', 'filterDropdownOpen', filterDropdownVisible],
@ -184,11 +184,10 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
onFilterDropdownVisibleChange,
],
].forEach(([deprecatedName, newName, prop]) => {
warning(
warning.deprecated(
prop === undefined || prop === null,
'Table',
'deprecated',
`\`${deprecatedName}\` is deprecated. Please use \`${newName}\` instead.`,
deprecatedName as string,
newName as string,
);
});
}

View File

@ -204,7 +204,7 @@ function useFilter<RecordType>({
FilterState<RecordType>[],
Record<string, FilterValue | null>,
] {
const warning = devUseWarning();
const warning = devUseWarning('Table');
const mergedColumns = React.useMemo(
() => getMergedColumns(rawMergedColumns || []),
@ -253,7 +253,6 @@ function useFilter<RecordType>({
warning(
filteredKeysIsAllControlled,
'Table',
'usage',
'Columns should all contain `filteredValue` or not contain `filteredValue`.',
);

View File

@ -107,7 +107,7 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
getPopupContainer,
} = config;
const warning = devUseWarning();
const warning = devUseWarning('Table');
// ========================= Keys =========================
const [mergedSelectedKeys, setMergedSelectedKeys] = useMergedState(
@ -182,7 +182,6 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
warning(
!('checked' in checkboxProps || 'defaultChecked' in checkboxProps),
'Table',
'usage',
'Do not set `checked` or `defaultChecked` in `getCheckboxProps`. Please use `selectedRowKeys` instead.',
);
@ -321,12 +320,7 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
const keys = Array.from(keySet);
if (onSelectInvert) {
warning(
false,
'Table',
'deprecated',
'`onSelectInvert` will be removed in future. Please use `onChange` instead.',
);
warning.deprecated(false, 'onSelectInvert', 'onChange');
onSelectInvert(keys);
}
@ -368,7 +362,6 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
if (!rowSelection) {
warning(
!columns.includes(SELECTION_COLUMN),
'Table',
'usage',
'`rowSelection` is not config but `SELECTION_COLUMN` exists in the `columns`.',
);
@ -522,7 +515,6 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
mergedIndeterminate = indeterminate;
warning(
typeof checkboxProps?.indeterminate !== 'boolean',
'Table',
'usage',
'set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured dataSource.',
);
@ -670,7 +662,6 @@ const useSelection = <RecordType extends AnyObject = AnyObject>(
warning(
cloneColumns.filter((col) => col === SELECTION_COLUMN).length <= 1,
'Table',
'usage',
'Multiple `SELECTION_COLUMN` exist in `columns`.',
);

View File

@ -122,7 +122,7 @@ describe('Tabs', () => {
expect(container.querySelectorAll('.ant-tabs-tab')).toHaveLength(1);
expect(errorSpy).toHaveBeenCalledWith(
'Warning: [antd: Tabs] Tabs.TabPane is deprecated. Please use `items` directly.',
'Warning: [antd: Tabs] `Tabs.TabPane` is deprecated. Please use `items` instead.',
);
errorSpy.mockRestore();
});

View File

@ -11,13 +11,8 @@ function filter<T>(items: (T | null)[]): T[] {
export default function useLegacyItems(items?: TabsProps['items'], children?: React.ReactNode) {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
warning(
!children,
'Tabs',
'deprecated',
'Tabs.TabPane is deprecated. Please use `items` directly.',
);
const warning = devUseWarning('Tabs');
warning.deprecated(!children, 'Tabs.TabPane', 'items');
}
if (items) {

View File

@ -69,11 +69,10 @@ const Tabs: React.FC<TabsProps> & { TabPane: typeof TabPane } = (props) => {
const rootPrefixCls = getPrefixCls();
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Tabs');
warning(
!('onPrevClick' in props) && !('onNextClick' in props),
'Tabs',
'breaking',
'`onPrevClick` and `onNextClick` has been removed. Please use `onTabScroll` instead.',
);

View File

@ -147,7 +147,7 @@ describe('Tag', () => {
const { container } = render(<Tag visible={false} />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tag] `visible` is deprecated, please use `visible && <Tag />` instead.',
'Warning: [antd: Tag] `visible` is deprecated. Please use `visible && <Tag />` instead.',
);
expect(container.querySelector('.ant-tag-hidden')).toBeTruthy();

View File

@ -57,14 +57,9 @@ const InternalTag: React.ForwardRefRenderFunction<HTMLSpanElement, TagProps> = (
// Warning for deprecated usage
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Tag');
warning(
!('visible' in props),
'Tag',
'deprecated',
'`visible` is deprecated, please use `visible && <Tag />` instead.',
);
warning.deprecated(!('visible' in props), 'visible', 'visible && <Tag />');
}
React.useEffect(() => {

View File

@ -32,14 +32,9 @@ export interface TimePickerProps extends Omit<PickerTimeProps<Dayjs>, 'picker'>
const TimePicker = React.forwardRef<any, TimePickerProps>(
({ addon, renderExtraFooter, ...restProps }, ref) => {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('TimePicker');
warning(
!addon,
'TimePicker',
'deprecated',
'`addon` is deprecated. Please use `renderExtraFooter` instead.',
);
warning.deprecated(!addon, 'addon', 'renderExtraFooter');
}
const internalRenderExtraFooter = React.useMemo(() => {

View File

@ -35,14 +35,9 @@ const Timeline: CompoundedComponent = (props) => {
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Timeline');
warning(
!children,
'Timeline',
'deprecated',
'`Timeline.Item` is deprecated. Please use `items` instead.',
);
warning.deprecated(!children, 'Timeline.Item', 'items');
}
// Style

View File

@ -511,7 +511,7 @@ exports[`renders components/tooltip/demo/arrow-point-at-center.tsx extend contex
exports[`renders components/tooltip/demo/arrow-point-at-center.tsx extend context correctly 2`] = `
[
"Warning: [antd: Tooltip] \`arrowPointAtCenter\` is deprecated, please use \`arrow={{ pointAtCenter: true }}\` instead.",
"Warning: [antd: Tooltip] \`arrowPointAtCenter\` is deprecated. Please use \`arrow={{ pointAtCenter: true }}\` instead.",
]
`;

View File

@ -495,7 +495,7 @@ describe('Tooltip', () => {
await waitFakeTimer();
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tooltip] `defaultVisible` is deprecated, please use `defaultOpen` instead.',
'Warning: [antd: Tooltip] `defaultVisible` is deprecated. Please use `defaultOpen` instead.',
);
expect(isTooltipOpen()).toBeTruthy();
@ -506,7 +506,7 @@ describe('Tooltip', () => {
</Tooltip>,
);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tooltip] `visible` is deprecated, please use `open` instead.',
'Warning: [antd: Tooltip] `visible` is deprecated. Please use `open` instead.',
);
rerender(
@ -527,7 +527,7 @@ describe('Tooltip', () => {
</Tooltip>,
);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tooltip] `onVisibleChange` is deprecated, please use `onOpenChange` instead.',
'Warning: [antd: Tooltip] `onVisibleChange` is deprecated. Please use `onOpenChange` instead.',
);
// afterVisibleChange
@ -537,7 +537,7 @@ describe('Tooltip', () => {
</Tooltip>,
);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Tooltip] `afterVisibleChange` is deprecated, please use `afterOpenChange` instead.',
'Warning: [antd: Tooltip] `afterVisibleChange` is deprecated. Please use `afterOpenChange` instead.',
);
// Event Trigger

View File

@ -216,7 +216,7 @@ const Tooltip = React.forwardRef<TooltipRef, TooltipProps>((props, ref) => {
} = React.useContext(ConfigContext);
// ============================== Ref ===============================
const warning = devUseWarning();
const warning = devUseWarning('Tooltip');
const tooltipRef = React.useRef<RcTooltipRef>(null);
@ -227,12 +227,7 @@ const Tooltip = React.forwardRef<TooltipRef, TooltipProps>((props, ref) => {
React.useImperativeHandle(ref, () => ({
forceAlign,
forcePopupAlign: () => {
warning(
false,
'Tooltip',
'deprecated',
'`forcePopupAlign` is align to `forceAlign` instead.',
);
warning.deprecated(false, 'forcePopupAlign', 'forceAlign');
forceAlign();
},
}));
@ -246,26 +241,19 @@ const Tooltip = React.forwardRef<TooltipRef, TooltipProps>((props, ref) => {
['afterVisibleChange', 'afterOpenChange'],
['arrowPointAtCenter', 'arrow={{ pointAtCenter: true }}'],
].forEach(([deprecatedName, newName]) => {
warning(
!(deprecatedName in props),
'Tooltip',
'deprecated',
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
);
warning.deprecated(!(deprecatedName in props), deprecatedName, newName);
});
warning(
!destroyTooltipOnHide || typeof destroyTooltipOnHide === 'boolean',
'Tooltip',
'usage',
'`destroyTooltipOnHide` no need config `keepParent` anymore. Please use `boolean` value directly.',
);
warning(
!arrow || typeof arrow === 'boolean' || !('arrowPointAtCenter' in arrow),
'Tooltip',
'deprecated',
'`arrowPointAtCenter` in `arrow` is deprecated, please use `pointAtCenter` instead.',
'`arrowPointAtCenter` in `arrow` is deprecated. Please use `pointAtCenter` instead.',
);
}

View File

@ -170,14 +170,9 @@ const Transfer = <RecordType extends TransferItem = TransferItem>(
] = useSelection(leftDataSource, rightDataSource, selectedKeys);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Transfer');
warning(
!pagination || !children,
'Transfer',
'usage',
'`pagination` not support customize render list.',
);
warning(!pagination || !children, 'usage', '`pagination` not support customize render list.');
}
const setStateKeys = useCallback(

View File

@ -1637,7 +1637,7 @@ Array [
exports[`renders components/tree-select/demo/placement.tsx extend context correctly 2`] = `
[
"Warning: [antd: Select] \`dropdownMatchSelectWidth\` is deprecated. Please use \`popupMatchSelectWidth\` instead.",
"Warning: [antd: TreeSelect] \`dropdownMatchSelectWidth\` is deprecated. Please use \`popupMatchSelectWidth\` instead.",
]
`;

View File

@ -72,7 +72,7 @@ describe('TreeSelect', () => {
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
render(<TreeSelect dropdownMatchSelectWidth open />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Select] `dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
'Warning: [antd: TreeSelect] `dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
);
errSpy.mockRestore();

View File

@ -121,32 +121,24 @@ const InternalTreeSelect = <
} = React.useContext(ConfigContext);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('TreeSelect');
warning(
multiple !== false || !treeCheckable,
'TreeSelect',
'usage',
'`multiple` will always be `true` when `treeCheckable` is true',
);
warning(
!dropdownClassName,
'TreeSelect',
'deprecated',
'`dropdownClassName` is deprecated. Please use `popupClassName` instead.',
);
warning.deprecated(!dropdownClassName, 'dropdownClassName', 'popupClassName');
warning(
warning.deprecated(
dropdownMatchSelectWidth === undefined,
'Select',
'deprecated',
'`dropdownMatchSelectWidth` is deprecated. Please use `popupMatchSelectWidth` instead.',
'dropdownMatchSelectWidth',
'popupMatchSelectWidth',
);
warning(
!('showArrow' in props),
'TreeSelect',
'deprecated',
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.',
);

View File

@ -12,14 +12,9 @@ export interface LinkProps
const Link = React.forwardRef<HTMLElement, LinkProps>(({ ellipsis, rel, ...restProps }, ref) => {
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Typography.Link');
warning(
typeof ellipsis !== 'object',
'Typography.Link',
'usage',
'`ellipsis` only supports boolean value.',
);
warning(typeof ellipsis !== 'object', 'usage', '`ellipsis` only supports boolean value.');
}
const mergedProps = {

View File

@ -24,13 +24,12 @@ const Text: React.ForwardRefRenderFunction<HTMLSpanElement, TextProps> = (
}, [ellipsis]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Typography.Text');
warning(
typeof ellipsis !== 'object' ||
!ellipsis ||
(!('expandable' in ellipsis) && !('rows' in ellipsis)),
'Typography.Text',
'usage',
'`ellipsis` do not support `expandable` or `rows` props.',
);

View File

@ -20,11 +20,10 @@ const Title = React.forwardRef<HTMLElement, TitleProps>((props, ref) => {
let component: keyof JSX.IntrinsicElements;
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Typography.Title');
warning(
TITLE_ELE_LIST.includes(level),
'Typography.Title',
'usage',
'Title only accept `1 | 2 | 3 | 4 | 5` as `level` value. And `5` need 4.6.0+ version.',
);

View File

@ -56,14 +56,9 @@ const Typography = React.forwardRef<
}
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Typography');
warning(
!setContentRef,
'Typography',
'deprecated',
'`setContentRef` is deprecated. Please use `ref` instead.',
);
warning.deprecated(!setContentRef, 'setContentRef', 'ref');
}
const prefixCls = getPrefixCls('typography', customizePrefixCls);

View File

@ -80,21 +80,15 @@ const InternalUpload: React.ForwardRefRenderFunction<UploadRef, UploadProps> = (
const upload = React.useRef<RcUpload>(null);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning();
const warning = devUseWarning('Upload');
warning(
'fileList' in props || !('value' in props),
'Upload',
'usage',
'`value` is not a valid prop, do you mean `fileList`?',
);
warning(
!('transformFile' in props),
'Upload',
'deprecated',
'`transformFile` is deprecated. Please use `beforeUpload` directly.',
);
warning.deprecated(!('transformFile' in props), 'transformFile', 'beforeUpload');
}
// Control mode will auto fill file uid if not provided

View File

@ -102,7 +102,7 @@ While the major version is being upgraded, some components are discarded, but th
++ const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
++ render(<BackTop />);
++ expect(errSpy).toHaveBeenCalledWith(
++ 'Warning: [antd: BackTop] `BackTop` is deprecated, please use `FloatButton.BackTop` instead.',
++ 'Warning: [antd: BackTop] `BackTop` is deprecated. Please use `FloatButton.BackTop` instead.',
++ );
++ errSpy.mockRestore();
++ });

View File

@ -102,7 +102,7 @@ author: li-jia-nan,zombieJ
++ const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
++ render(<BackTop />);
++ expect(errSpy).toHaveBeenCalledWith(
++ 'Warning: [antd: BackTop] `BackTop` is deprecated, please use `FloatButton.BackTop` instead.',
++ 'Warning: [antd: BackTop] `BackTop` is deprecated. Please use `FloatButton.BackTop` instead.',
++ );
++ errSpy.mockRestore();
++ });