mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
chore: support deprecated visible in v5 but warning with this (#37422)
* chore: tags deprecated support * chore: Slider Tooltip test * chore: Table dropdown visible legacy * chore: drawer warning of legacy * chore: Modal legacy prop * chore: dropdown open legacy prop * chore: Tooltiop visible legacy info * fix: format logic * test: Update test for 18 * chore: fix lint
This commit is contained in:
parent
f85c68f4be
commit
44d8076304
@ -106,7 +106,7 @@ describe('Drawer', () => {
|
||||
expect(container.querySelector('.ant-drawer-content-wrapper-hidden')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('test afterVisibleChange', async () => {
|
||||
it('test afterOpenChange', async () => {
|
||||
const afterOpenChange = jest.fn();
|
||||
const { container, rerender } = render(<DrawerTest open afterOpenChange={afterOpenChange} />);
|
||||
rerender(<DrawerTest open={false} afterOpenChange={afterOpenChange} />);
|
||||
@ -119,6 +119,31 @@ describe('Drawer', () => {
|
||||
expect(afterOpenChange).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('test legacy afterVisibleChange', async () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const afterVisibleChange = jest.fn();
|
||||
const { container, rerender } = render(
|
||||
<DrawerTest open afterVisibleChange={afterVisibleChange} />,
|
||||
);
|
||||
rerender(<DrawerTest visible={false} afterVisibleChange={afterVisibleChange} />);
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
fireEvent.animationEnd(container.querySelector('.ant-drawer-content-wrapper')!);
|
||||
|
||||
expect(afterVisibleChange).toHaveBeenCalledTimes(1);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Drawer] `visible` is deprecated, please use `open` instead.',
|
||||
);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Drawer] `afterVisibleChange` is deprecated, please use `afterOpenChange` instead.',
|
||||
);
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('should support children ref', () => {
|
||||
const fn = jest.fn();
|
||||
|
||||
|
@ -39,6 +39,12 @@ export interface DrawerProps extends RcDrawerProps {
|
||||
extra?: React.ReactNode;
|
||||
|
||||
afterOpenChange?: (open: boolean) => void;
|
||||
|
||||
// Deprecated
|
||||
/** @deprecated Please use `open` instead */
|
||||
visible?: boolean;
|
||||
/** @deprecated Please use `afterOpenChange` instead */
|
||||
afterVisibleChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
const defaultPushState: PushState = { distance: 180 };
|
||||
@ -56,6 +62,7 @@ function Drawer(props: DrawerProps) {
|
||||
bodyStyle,
|
||||
drawerStyle,
|
||||
open,
|
||||
afterOpenChange,
|
||||
children,
|
||||
title,
|
||||
headerStyle,
|
||||
@ -65,6 +72,11 @@ function Drawer(props: DrawerProps) {
|
||||
prefixCls: customizePrefixCls,
|
||||
getContainer: customizeGetContainer,
|
||||
extra,
|
||||
|
||||
// Deprecated
|
||||
visible,
|
||||
afterVisibleChange,
|
||||
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
@ -86,17 +98,6 @@ function Drawer(props: DrawerProps) {
|
||||
</button>
|
||||
);
|
||||
|
||||
[
|
||||
['visible', 'open'],
|
||||
['afterVisibleChange', 'afterOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Drawer',
|
||||
`\`${deprecatedName}\` is deprecated which will be removed in next major version, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
|
||||
function renderHeader() {
|
||||
if (!title && !closable) {
|
||||
return null;
|
||||
@ -149,7 +150,7 @@ function Drawer(props: DrawerProps) {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Drawer',
|
||||
`\`${deprecatedName}\` is removed, please use \`${newName}\` instead.`,
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -187,13 +188,14 @@ function Drawer(props: DrawerProps) {
|
||||
maskMotion={maskMotion}
|
||||
motion={panelMotion}
|
||||
{...rest}
|
||||
open={open}
|
||||
open={open ?? visible}
|
||||
mask={mask}
|
||||
push={push}
|
||||
width={mergedWidth}
|
||||
height={mergedHeight}
|
||||
rootClassName={drawerClassName}
|
||||
getContainer={getContainer}
|
||||
afterOpenChange={afterOpenChange ?? afterVisibleChange}
|
||||
>
|
||||
<div className={`${prefixCls}-wrapper-body`} style={{ ...drawerStyle }}>
|
||||
{renderHeader()}
|
||||
|
@ -6,6 +6,7 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { act, fireEvent, render, sleep } from '../../../tests/utils';
|
||||
import Menu from '../../menu';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
|
||||
let triggerProps: TriggerProps;
|
||||
|
||||
@ -167,4 +168,37 @@ describe('Dropdown', () => {
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('legacy visible', () => {
|
||||
resetWarned();
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
const onOpenChange = jest.fn();
|
||||
const onVisibleChange = jest.fn();
|
||||
|
||||
const { container } = render(
|
||||
<Dropdown
|
||||
visible
|
||||
onOpenChange={onOpenChange}
|
||||
onVisibleChange={onVisibleChange}
|
||||
trigger={['click']}
|
||||
overlay={<div className="bamboo" />}
|
||||
>
|
||||
<a className="little" />
|
||||
</Dropdown>,
|
||||
);
|
||||
|
||||
expect(document.querySelector('.bamboo')).toBeTruthy();
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Dropdown] `visible` is deprecated, please use `open` instead.',
|
||||
);
|
||||
expect(errorSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Dropdown] `onVisibleChange` is deprecated, please use `onOpenChange` instead.',
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector('.little')!);
|
||||
expect(onOpenChange).toHaveBeenCalled();
|
||||
expect(onVisibleChange).toHaveBeenCalled();
|
||||
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -68,6 +68,12 @@ export interface DropdownProps {
|
||||
mouseLeaveDelay?: number;
|
||||
openClassName?: string;
|
||||
children?: React.ReactNode;
|
||||
|
||||
// Deprecated
|
||||
/** @deprecated Please use `open` instead */
|
||||
visible?: boolean;
|
||||
/** @deprecated Please use `onOpenChange` instead */
|
||||
onVisibleChange?: (open: boolean) => void;
|
||||
}
|
||||
|
||||
interface DropdownInterface extends React.FC<DropdownProps> {
|
||||
@ -82,17 +88,6 @@ const Dropdown: DropdownInterface = props => {
|
||||
direction,
|
||||
} = React.useContext(ConfigContext);
|
||||
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Dropdown',
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
|
||||
const getTransitionName = () => {
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
const { placement = '', transitionName } = props;
|
||||
@ -134,8 +129,25 @@ const Dropdown: DropdownInterface = props => {
|
||||
overlayClassName,
|
||||
open,
|
||||
onOpenChange,
|
||||
|
||||
// Deprecated
|
||||
visible,
|
||||
onVisibleChange,
|
||||
} = props;
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['visible', 'open'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Dropdown',
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const prefixCls = getPrefixCls('dropdown', customizePrefixCls);
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
|
||||
@ -160,11 +172,12 @@ const Dropdown: DropdownInterface = props => {
|
||||
|
||||
// =========================== Open ============================
|
||||
const [mergedOpen, setOpen] = useMergedState(false, {
|
||||
value: open,
|
||||
value: open ?? visible,
|
||||
});
|
||||
|
||||
const onInnerOpenChange = useEvent((nextOpen: boolean) => {
|
||||
onOpenChange?.(nextOpen);
|
||||
onVisibleChange?.(nextOpen);
|
||||
setOpen(nextOpen);
|
||||
});
|
||||
|
||||
|
@ -82,6 +82,10 @@ export interface ModalProps {
|
||||
modalRender?: (node: React.ReactNode) => React.ReactNode;
|
||||
focusTriggerAfterClose?: boolean;
|
||||
children?: React.ReactNode;
|
||||
|
||||
// Legacy
|
||||
/** @deprecated Please use `open` instead. */
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
type getContainerFunc = () => HTMLElement;
|
||||
@ -148,14 +152,6 @@ const Modal: React.FC<ModalProps> = props => {
|
||||
onOk?.(e);
|
||||
};
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(
|
||||
!('visible' in props),
|
||||
'Modal',
|
||||
`\`visible\` is removed in v5, please use \`open\` instead.`,
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
className,
|
||||
@ -165,6 +161,10 @@ const Modal: React.FC<ModalProps> = props => {
|
||||
getContainer,
|
||||
closeIcon,
|
||||
focusTriggerAfterClose = true,
|
||||
|
||||
// Deprecated
|
||||
visible,
|
||||
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
@ -178,11 +178,9 @@ const Modal: React.FC<ModalProps> = props => {
|
||||
[`${prefixCls}-wrap-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
warning(
|
||||
!('visible' in props),
|
||||
'Modal',
|
||||
`\`visible\` is deprecated, please use \`open\` instead.`,
|
||||
);
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(!('visible' in props), 'Modal', '`visible` is deprecated, please use `open` instead.');
|
||||
}
|
||||
|
||||
return wrapSSR(
|
||||
<NoFormStyle status override>
|
||||
@ -199,7 +197,7 @@ const Modal: React.FC<ModalProps> = props => {
|
||||
onOk: handleOk,
|
||||
onCancel: handleCancel,
|
||||
})}
|
||||
visible={open}
|
||||
visible={open ?? visible}
|
||||
mousePosition={mousePosition}
|
||||
onClose={handleCancel}
|
||||
closeIcon={renderCloseIcon(prefixCls, closeIcon)}
|
||||
@ -215,7 +213,6 @@ const Modal: React.FC<ModalProps> = props => {
|
||||
Modal.defaultProps = {
|
||||
width: 520,
|
||||
confirmLoading: false,
|
||||
open: false,
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
|
@ -96,11 +96,13 @@ describe('Modal', () => {
|
||||
resetWarned();
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
render(<Modal {...({ visible: true } as any)} />);
|
||||
render(<Modal visible />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Modal] `visible` is removed in v5, please use `open` instead.',
|
||||
'Warning: [antd: Modal] `visible` is deprecated, please use `open` instead.',
|
||||
);
|
||||
|
||||
expect(document.querySelector('.ant-modal')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -168,27 +168,58 @@ describe('Slider', () => {
|
||||
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const { rerender } = render(<TSSlider tooltipPrefixCls="xxx" />);
|
||||
const { container, rerender } = render(<TSSlider tooltipPrefixCls="xxx" />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Slider] `tooltipPrefixCls` is removed in v5, 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 removed in v5, 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 removed in v5, 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 removed in v5, 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 removed in v5, please use `tooltip.placement` instead.',
|
||||
'Warning: [antd: Slider] `tooltipPlacement` is deprecated, please use `tooltip.placement` instead.',
|
||||
);
|
||||
|
||||
// All should work
|
||||
const holder = document.createElement('div');
|
||||
holder.id = 'holder';
|
||||
document.body.appendChild(holder);
|
||||
|
||||
const getTooltipPopupContainer = jest.fn(() => container);
|
||||
|
||||
rerender(
|
||||
<TSSlider
|
||||
tooltipPrefixCls="bamboo"
|
||||
getTooltipPopupContainer={getTooltipPopupContainer}
|
||||
tipFormatter={() => 'little'}
|
||||
tooltipPlacement="bottom"
|
||||
tooltipVisible
|
||||
/>,
|
||||
);
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(getTooltipPopupContainer).toHaveBeenCalled();
|
||||
expect(container.querySelector('.bamboo')).toBeTruthy();
|
||||
expect(container.querySelector('.bamboo-inner')!.textContent).toEqual('little');
|
||||
|
||||
holder.parentNode?.removeChild(holder);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -23,12 +23,15 @@ export type HandleGeneratorFn = (config: {
|
||||
info: HandleGeneratorInfo;
|
||||
}) => React.ReactElement;
|
||||
|
||||
export type Formatter = (value?: number) => React.ReactNode;
|
||||
const defaultFormatter: Formatter = val => (typeof val === 'number' ? val.toString() : '');
|
||||
|
||||
export interface SliderTooltipProps {
|
||||
prefixCls?: string;
|
||||
open?: boolean;
|
||||
placement?: TooltipPlacement;
|
||||
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
||||
formatter?: null | ((value?: number) => React.ReactNode);
|
||||
formatter?: null | Formatter;
|
||||
}
|
||||
|
||||
export interface SliderBaseProps {
|
||||
@ -47,6 +50,21 @@ export interface SliderBaseProps {
|
||||
style?: React.CSSProperties;
|
||||
tooltip?: SliderTooltipProps;
|
||||
autoFocus?: boolean;
|
||||
|
||||
// Deprecated
|
||||
/** @deprecated `tooltipPrefixCls` is deprecated. Please use `tooltip.prefixCls` instead. */
|
||||
tooltipPrefixCls?: string;
|
||||
/** @deprecated `tipFormatter` is deprecated. Please use `tooltip.formatter` instead. */
|
||||
tipFormatter?: null | ((value?: number) => React.ReactNode);
|
||||
/** @deprecated `tooltipVisible` is deprecated. Please use `tooltip.open` instead. */
|
||||
tooltipVisible?: boolean;
|
||||
/**
|
||||
* @deprecated `getTooltipPopupContainer` is deprecated. Please use `tooltip.getPopupContainer`
|
||||
* instead.
|
||||
*/
|
||||
getTooltipPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
|
||||
/** @deprecated `tooltipPlacement` is deprecated. Please use `tooltip.placement` instead. */
|
||||
tooltipPlacement?: TooltipPlacement;
|
||||
}
|
||||
|
||||
export interface SliderSingleProps extends SliderBaseProps {
|
||||
@ -77,6 +95,21 @@ export type Opens = { [index: number]: boolean };
|
||||
|
||||
const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
(props, ref: any) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
range,
|
||||
className,
|
||||
|
||||
// Deprecated Props
|
||||
tooltipPrefixCls: legacyTooltipPrefixCls,
|
||||
tipFormatter: legacyTipFormatter,
|
||||
tooltipVisible: legacyTooltipVisible,
|
||||
getTooltipPopupContainer: legacyGetTooltipPopupContainer,
|
||||
tooltipPlacement: legacyTooltipPlacement,
|
||||
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
const { getPrefixCls, direction, getPopupContainer } = React.useContext(ConfigContext);
|
||||
const [opens, setOpens] = React.useState<Opens>({});
|
||||
|
||||
@ -84,9 +117,9 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
setOpens((prev: Opens) => ({ ...prev, [index]: open }));
|
||||
};
|
||||
|
||||
const getTooltipPlacement = (tooltipPlacement?: TooltipPlacement, vertical?: boolean) => {
|
||||
if (tooltipPlacement) {
|
||||
return tooltipPlacement;
|
||||
const getTooltipPlacement = (placement?: TooltipPlacement, vertical?: boolean) => {
|
||||
if (placement) {
|
||||
return placement;
|
||||
}
|
||||
if (!vertical) {
|
||||
return 'top';
|
||||
@ -94,7 +127,6 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
return direction === 'rtl' ? 'left' : 'right';
|
||||
};
|
||||
|
||||
const { prefixCls: customizePrefixCls, range, className, ...restProps } = props;
|
||||
const prefixCls = getPrefixCls('slider', customizePrefixCls);
|
||||
|
||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||
@ -133,7 +165,7 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Slider',
|
||||
`\`${deprecatedName}\` is removed in v5, please use \`tooltip.${newName}\` instead.`,
|
||||
`\`${deprecatedName}\` is deprecated, please use \`tooltip.${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -145,9 +177,6 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
const { tooltip = {}, vertical } = props;
|
||||
|
||||
const tooltipProps: SliderTooltipProps = {
|
||||
formatter(value) {
|
||||
return typeof value === 'number' ? value.toString() : '';
|
||||
},
|
||||
...tooltip,
|
||||
};
|
||||
const {
|
||||
@ -158,8 +187,18 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
formatter: tipFormatter,
|
||||
} = tooltipProps;
|
||||
|
||||
const isTipFormatter = tipFormatter ? opens[index] || dragging : false;
|
||||
const open = tooltipOpen || (tooltipOpen === undefined && isTipFormatter);
|
||||
let mergedTipFormatter = tipFormatter;
|
||||
if (tipFormatter || tipFormatter === null) {
|
||||
mergedTipFormatter = tipFormatter;
|
||||
} else if (legacyTipFormatter || legacyTipFormatter === null) {
|
||||
mergedTipFormatter = legacyTipFormatter;
|
||||
} else {
|
||||
mergedTipFormatter = defaultFormatter;
|
||||
}
|
||||
|
||||
const isTipFormatter = mergedTipFormatter ? opens[index] || dragging : false;
|
||||
const open =
|
||||
tooltipOpen ?? legacyTooltipVisible ?? (tooltipOpen === undefined && isTipFormatter);
|
||||
|
||||
const passedProps = {
|
||||
...node.props,
|
||||
@ -167,18 +206,23 @@ const Slider = React.forwardRef<unknown, SliderSingleProps | SliderRangeProps>(
|
||||
onMouseLeave: () => toggleTooltipOpen(index, false),
|
||||
};
|
||||
|
||||
const tooltipPrefixCls = getPrefixCls('tooltip', customizeTooltipPrefixCls);
|
||||
const tooltipPrefixCls = getPrefixCls(
|
||||
'tooltip',
|
||||
customizeTooltipPrefixCls ?? legacyTooltipPrefixCls,
|
||||
);
|
||||
|
||||
return (
|
||||
<SliderTooltip
|
||||
prefixCls={tooltipPrefixCls}
|
||||
title={tipFormatter ? tipFormatter(info.value) : ''}
|
||||
title={mergedTipFormatter ? mergedTipFormatter(info.value) : ''}
|
||||
open={open}
|
||||
placement={getTooltipPlacement(tooltipPlacement, vertical)}
|
||||
placement={getTooltipPlacement(tooltipPlacement ?? legacyTooltipPlacement, vertical)}
|
||||
transitionName={`${rootPrefixCls}-zoom-down`}
|
||||
key={index}
|
||||
overlayClassName={`${prefixCls}-tooltip`}
|
||||
getPopupContainer={getTooltipPopupContainer || getPopupContainer}
|
||||
getPopupContainer={
|
||||
getTooltipPopupContainer || legacyGetTooltipPopupContainer || getPopupContainer
|
||||
}
|
||||
>
|
||||
{React.cloneElement(node, passedProps)}
|
||||
</SliderTooltip>
|
||||
|
@ -140,28 +140,13 @@ function InternalTable<RecordType extends object = any>(
|
||||
showSorterTooltip = true,
|
||||
} = props;
|
||||
|
||||
warning(
|
||||
!(typeof rowKey === 'function' && rowKey.length > 1),
|
||||
'Table',
|
||||
'`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.',
|
||||
);
|
||||
warning(
|
||||
!('filterDropdownVisible' in props || 'onFilterDropdownVisibleChange' in props),
|
||||
'Table',
|
||||
'`filterDropdownVisible` and `onFilterDropdownVisibleChange` is deprecated, ' +
|
||||
'please use `filterDropdownOpen` and `onFilterDropdownOpenChange` instead.',
|
||||
);
|
||||
|
||||
[
|
||||
['filterDropdownVisible', 'filterDropdownOpen'],
|
||||
['onFilterDropdownVisibleChange', 'onFilterDropdownOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
!(typeof rowKey === 'function' && rowKey.length > 1),
|
||||
'Table',
|
||||
`\`${deprecatedName}\` is deprecated which will be removed in next major version.Please use \`${newName}\` instead. `,
|
||||
'`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.',
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const baseColumns = React.useMemo(
|
||||
() => columns || (convertChildrenToColumns(children) as ColumnsType<RecordType>),
|
||||
@ -277,7 +262,8 @@ function InternalTable<RecordType extends object = any>(
|
||||
/**
|
||||
* Controlled state in `columns` is not a good idea that makes too many code (1000+ line?) to read
|
||||
* state out and then put it back to title render. Move these code into `hooks` but still too
|
||||
* complex. We should provides Table props like `sorter` & `filter` to handle control in next big version.
|
||||
* complex. We should provides Table props like `sorter` & `filter` to handle control in next big
|
||||
* version.
|
||||
*/
|
||||
|
||||
// ============================ Sorter =============================
|
||||
|
@ -12,6 +12,7 @@ import Tooltip from '../../tooltip';
|
||||
import type { SelectProps } from '../../select';
|
||||
import type { ColumnGroupType, ColumnType, TableProps } from '..';
|
||||
import type { ColumnFilterItem, FilterDropdownProps, FilterValue } from '../interface';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
|
||||
// https://github.com/Semantic-Org/Semantic-UI-React/blob/72c45080e4f20b531fda2e3e430e384083d6766b/test/specs/modules/Dropdown/Dropdown-test.js#L73
|
||||
const nativeEvent = { nativeEvent: { stopImmediatePropagation: () => {} } };
|
||||
@ -281,6 +282,7 @@ describe('Table.filter', () => {
|
||||
}
|
||||
|
||||
test('filterDropdownOpen');
|
||||
test('filterDropdownVisible');
|
||||
});
|
||||
|
||||
it('if the filter is visible it should ignore the selectedKeys changes', () => {
|
||||
@ -333,19 +335,31 @@ describe('Table.filter', () => {
|
||||
});
|
||||
|
||||
it('fires change event when visible change', () => {
|
||||
resetWarned();
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const onFilterDropdownOpenChange = jest.fn();
|
||||
const onFilterDropdownVisibleChange = jest.fn();
|
||||
const { container } = render(
|
||||
createTable({
|
||||
columns: [
|
||||
{
|
||||
...column,
|
||||
onFilterDropdownOpenChange,
|
||||
onFilterDropdownVisibleChange,
|
||||
},
|
||||
],
|
||||
}),
|
||||
);
|
||||
fireEvent.click(container.querySelector('.ant-dropdown-trigger')!);
|
||||
expect(onFilterDropdownOpenChange).toHaveBeenCalledWith(true);
|
||||
expect(onFilterDropdownVisibleChange).toHaveBeenCalledWith(true);
|
||||
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Table] `onFilterDropdownVisibleChange` is deprecated. Please use `onFilterDropdownOpenChange` instead.',
|
||||
);
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('can be controlled by filteredValue', () => {
|
||||
|
@ -28,6 +28,7 @@ import type {
|
||||
} from '../../interface';
|
||||
import FilterSearch from './FilterSearch';
|
||||
import FilterDropdownMenuWrapper from './FilterWrapper';
|
||||
import warning from '../../../_util/warning';
|
||||
|
||||
type FilterTreeDataNode = FieldDataNode<{ title: React.ReactNode; key: React.Key }>;
|
||||
|
||||
@ -141,6 +142,10 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
|
||||
onFilterDropdownOpenChange,
|
||||
filterResetToDefaultFilteredValue,
|
||||
defaultFilteredValue,
|
||||
|
||||
// Deprecated
|
||||
filterDropdownVisible,
|
||||
onFilterDropdownVisibleChange,
|
||||
} = column;
|
||||
const [visible, setVisible] = React.useState(false);
|
||||
|
||||
@ -151,9 +156,27 @@ function FilterDropdown<RecordType>(props: FilterDropdownProps<RecordType>) {
|
||||
const triggerVisible = (newVisible: boolean) => {
|
||||
setVisible(newVisible);
|
||||
onFilterDropdownOpenChange?.(newVisible);
|
||||
onFilterDropdownVisibleChange?.(newVisible);
|
||||
};
|
||||
|
||||
const mergedVisible = typeof filterDropdownOpen === 'boolean' ? filterDropdownOpen : visible;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['filterDropdownVisible', 'filterDropdownOpen', filterDropdownVisible],
|
||||
[
|
||||
'onFilterDropdownVisibleChange',
|
||||
'onFilterDropdownOpenChange',
|
||||
onFilterDropdownVisibleChange,
|
||||
],
|
||||
].forEach(([deprecatedName, newName, prop]) => {
|
||||
warning(
|
||||
prop === undefined || prop === null,
|
||||
'Table',
|
||||
`\`${deprecatedName}\` is deprecated. Please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const mergedVisible = filterDropdownOpen ?? filterDropdownVisible ?? visible;
|
||||
|
||||
// ===================== Select Keys =====================
|
||||
const propFilteredKeys = filterState?.filteredKeys;
|
||||
|
@ -120,6 +120,12 @@ export interface ColumnType<RecordType> extends Omit<RcColumnType<RecordType>, '
|
||||
|
||||
// Responsive
|
||||
responsive?: Breakpoint[];
|
||||
|
||||
// Deprecated
|
||||
/** @deprecated Please use `filterDropdownOpen` instead */
|
||||
filterDropdownVisible?: boolean;
|
||||
/** @deprecated Please use `onFilterDropdownOpenChange` instead */
|
||||
onFilterDropdownVisibleChange?: (visible: boolean) => void;
|
||||
}
|
||||
|
||||
export interface ColumnGroupType<RecordType> extends Omit<ColumnType<RecordType>, 'dataIndex'> {
|
||||
|
@ -86,10 +86,11 @@ describe('Tag', () => {
|
||||
resetWarned();
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
render(<Tag visible />);
|
||||
const { container } = render(<Tag visible={false} />);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Tag] `visible` is removed, please use `visible && <Tag />` instead.',
|
||||
'Warning: [antd: Tag] `visible` is deprecated, please use `visible && <Tag />` instead.',
|
||||
);
|
||||
expect(container.querySelector('.ant-tag-hidden')).toBeTruthy();
|
||||
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
|
@ -20,6 +20,8 @@ export interface TagProps extends React.HTMLAttributes<HTMLSpanElement> {
|
||||
color?: LiteralUnion<PresetColorType | PresetStatusColorType, string>;
|
||||
closable?: boolean;
|
||||
closeIcon?: React.ReactNode;
|
||||
/** @deprecated `visible` will be removed in next major version. */
|
||||
visible?: boolean;
|
||||
onClose?: (e: React.MouseEvent<HTMLElement>) => void;
|
||||
style?: React.CSSProperties;
|
||||
icon?: React.ReactNode;
|
||||
@ -51,6 +53,21 @@ const InternalTag: React.ForwardRefRenderFunction<HTMLSpanElement, TagProps> = (
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const [visible, setVisible] = React.useState(true);
|
||||
|
||||
// Warning for deprecated usage
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
warning(
|
||||
!('visible' in props),
|
||||
'Tag',
|
||||
'`visible` is deprecated, please use `visible && <Tag />` instead.',
|
||||
);
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if ('visible' in props) {
|
||||
setVisible(props.visible!);
|
||||
}
|
||||
}, [props.visible]);
|
||||
|
||||
const isPresetColor = (): boolean => {
|
||||
if (!color) {
|
||||
return false;
|
||||
@ -103,12 +120,6 @@ const InternalTag: React.ForwardRefRenderFunction<HTMLSpanElement, TagProps> = (
|
||||
return null;
|
||||
};
|
||||
|
||||
warning(
|
||||
!('visible' in props),
|
||||
'Tag',
|
||||
'`visible` is removed, please use `visible && <Tag />` instead.',
|
||||
);
|
||||
|
||||
const isNeedWave =
|
||||
'onClick' in props || (children && (children as React.ReactElement<any>).type === 'a');
|
||||
const iconNode = icon || null;
|
||||
|
@ -4,13 +4,14 @@ import type { TooltipPlacement } from '..';
|
||||
import Tooltip from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { fireEvent, render, sleep, waitFor } from '../../../tests/utils';
|
||||
import { fireEvent, render, sleep, waitFor, act } from '../../../tests/utils';
|
||||
import Button from '../../button';
|
||||
import DatePicker from '../../date-picker';
|
||||
import Input from '../../input';
|
||||
import Group from '../../input/Group';
|
||||
import Switch from '../../switch';
|
||||
import Radio from '../../radio';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
|
||||
describe('Tooltip', () => {
|
||||
mountTest(Tooltip);
|
||||
@ -451,34 +452,61 @@ describe('Tooltip', () => {
|
||||
});
|
||||
|
||||
it('deprecated warning', () => {
|
||||
resetWarned();
|
||||
jest.useFakeTimers();
|
||||
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const { rerender } = render(
|
||||
<Tooltip visible>
|
||||
// defaultVisible
|
||||
const { container, rerender } = render(
|
||||
<Tooltip defaultVisible title="bamboo">
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Tooltip] `defaultVisible` is deprecated, please use `defaultOpen` instead.',
|
||||
);
|
||||
expect(document.querySelector('.ant-tooltip')).toBeTruthy();
|
||||
|
||||
// visible
|
||||
rerender(
|
||||
<Tooltip visible title="bamboo">
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Tooltip] `visible` is deprecated, please use `open` instead.',
|
||||
);
|
||||
|
||||
rerender(
|
||||
<Tooltip defaultVisible>
|
||||
<Tooltip visible={false} title="bamboo">
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Tooltip] `defaultVisible` is deprecated, please use `defaultOpen` instead.',
|
||||
);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
if (container.querySelector('.ant-zoom-big-fast-leave-active')) {
|
||||
fireEvent.animationEnd(container.querySelector('.ant-zoom-big-fast-leave-active')!);
|
||||
}
|
||||
expect(document.querySelector('.ant-tooltip-hidden')).toBeTruthy();
|
||||
|
||||
// onVisibleChange
|
||||
rerender(
|
||||
<Tooltip onVisibleChange={() => {}}>
|
||||
<Tooltip onVisibleChange={() => {}} title="bamboo">
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
expect(errSpy).toHaveBeenCalledWith(
|
||||
'Warning: [antd: Tooltip] `onVisibleChange` is deprecated, please use `onOpenChange` instead.',
|
||||
);
|
||||
|
||||
// afterVisibleChange
|
||||
rerender(
|
||||
<Tooltip afterVisibleChange={() => {}}>
|
||||
<Tooltip afterVisibleChange={() => {}} title="bamboo">
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
@ -486,6 +514,28 @@ describe('Tooltip', () => {
|
||||
'Warning: [antd: Tooltip] `afterVisibleChange` is deprecated, please use `afterOpenChange` instead.',
|
||||
);
|
||||
|
||||
// Event Trigger
|
||||
const onVisibleChange = jest.fn();
|
||||
const afterVisibleChange = jest.fn();
|
||||
rerender(
|
||||
<Tooltip
|
||||
visible
|
||||
onVisibleChange={onVisibleChange}
|
||||
afterVisibleChange={afterVisibleChange}
|
||||
title="bamboo"
|
||||
>
|
||||
<a />
|
||||
</Tooltip>,
|
||||
);
|
||||
|
||||
fireEvent.mouseLeave(container.querySelector('a')!);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(onVisibleChange).toHaveBeenCalled();
|
||||
expect(afterVisibleChange).toHaveBeenCalled();
|
||||
|
||||
jest.useRealTimers();
|
||||
errSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -51,30 +51,20 @@ interface LegacyTooltipProps
|
||||
'children' | 'visible' | 'defaultVisible' | 'onVisibleChange' | 'afterVisibleChange'
|
||||
>
|
||||
> {
|
||||
/**
|
||||
* @deprecated `visible` is deprecated which will be removed in next major version. Please use
|
||||
* `open` instead.
|
||||
*/
|
||||
visible?: RcTooltipProps['visible'];
|
||||
open?: RcTooltipProps['visible'];
|
||||
/**
|
||||
* @deprecated `defaultVisible` is deprecated which will be removed in next major version. Please
|
||||
* use `defaultOpen` instead.
|
||||
*/
|
||||
defaultVisible?: RcTooltipProps['defaultVisible'];
|
||||
defaultOpen?: RcTooltipProps['defaultVisible'];
|
||||
/**
|
||||
* @deprecated `onVisibleChange` is deprecated which will be removed in next major version. Please
|
||||
* use `onOpenChange` instead.
|
||||
*/
|
||||
onVisibleChange?: RcTooltipProps['onVisibleChange'];
|
||||
onOpenChange?: RcTooltipProps['onVisibleChange'];
|
||||
/**
|
||||
* @deprecated `afterVisibleChange` is deprecated which will be removed in next major version.
|
||||
* Please use `afterOpenChange` instead.
|
||||
*/
|
||||
afterVisibleChange?: RcTooltipProps['afterVisibleChange'];
|
||||
afterOpenChange?: RcTooltipProps['afterVisibleChange'];
|
||||
|
||||
// Legacy
|
||||
/** @deprecated Please use `open` instead. */
|
||||
visible?: RcTooltipProps['visible'];
|
||||
/** @deprecated Please use `defaultOpen` instead. */
|
||||
defaultVisible?: RcTooltipProps['defaultVisible'];
|
||||
/** @deprecated Please use `onOpenChange` instead. */
|
||||
onVisibleChange?: RcTooltipProps['onVisibleChange'];
|
||||
/** @deprecated Please use `afterOpenChange` instead. */
|
||||
afterVisibleChange?: RcTooltipProps['afterVisibleChange'];
|
||||
}
|
||||
|
||||
export interface AbstractTooltipProps extends LegacyTooltipProps {
|
||||
@ -166,28 +156,42 @@ function getDisabledCompatibleChildren(element: React.ReactElement<any>, prefixC
|
||||
}
|
||||
|
||||
const Tooltip = React.forwardRef<unknown, TooltipProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
openClassName,
|
||||
getTooltipContainer,
|
||||
overlayClassName,
|
||||
color,
|
||||
overlayInnerStyle,
|
||||
children,
|
||||
afterOpenChange,
|
||||
afterVisibleChange,
|
||||
} = props;
|
||||
|
||||
const {
|
||||
getPopupContainer: getContextPopupContainer,
|
||||
getPrefixCls,
|
||||
direction,
|
||||
} = React.useContext(ConfigContext);
|
||||
|
||||
[
|
||||
['visible', 'open'],
|
||||
['defaultVisible', 'defaultOpen'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
['afterVisibleChange', 'afterOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Tooltip',
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
[
|
||||
['visible', 'open'],
|
||||
['defaultVisible', 'defaultOpen'],
|
||||
['onVisibleChange', 'onOpenChange'],
|
||||
['afterVisibleChange', 'afterOpenChange'],
|
||||
].forEach(([deprecatedName, newName]) => {
|
||||
warning(
|
||||
!(deprecatedName in props),
|
||||
'Tooltip',
|
||||
`\`${deprecatedName}\` is deprecated, please use \`${newName}\` instead.`,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
const [open, setOpen] = useMergedState(false, {
|
||||
value: props.open,
|
||||
defaultValue: props.defaultOpen,
|
||||
value: props.open ?? props.visible,
|
||||
defaultValue: props.defaultOpen ?? props.defaultVisible,
|
||||
});
|
||||
|
||||
const isNoTitle = () => {
|
||||
@ -256,15 +260,6 @@ const Tooltip = React.forwardRef<unknown, TooltipProps>((props, ref) => {
|
||||
|
||||
const { getPopupContainer, overlayStyle, ...otherProps } = props;
|
||||
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
openClassName,
|
||||
getTooltipContainer,
|
||||
overlayClassName,
|
||||
color,
|
||||
overlayInnerStyle,
|
||||
children,
|
||||
} = props;
|
||||
const prefixCls = getPrefixCls('tooltip', customizePrefixCls);
|
||||
const rootPrefixCls = getPrefixCls();
|
||||
|
||||
@ -272,7 +267,7 @@ const Tooltip = React.forwardRef<unknown, TooltipProps>((props, ref) => {
|
||||
|
||||
let tempOpen = open;
|
||||
// Hide tooltip when there is no title
|
||||
if (!('open' in props) && isNoTitle()) {
|
||||
if (!('open' in props) && !('visible' in props) && isNoTitle()) {
|
||||
tempOpen = false;
|
||||
}
|
||||
|
||||
@ -320,6 +315,7 @@ const Tooltip = React.forwardRef<unknown, TooltipProps>((props, ref) => {
|
||||
overlay={getOverlay()}
|
||||
visible={tempOpen}
|
||||
onVisibleChange={onOpenChange}
|
||||
afterVisibleChange={afterOpenChange ?? afterVisibleChange}
|
||||
onPopupAlign={onPopupAlign}
|
||||
overlayInnerStyle={formattedOverlayInnerStyle}
|
||||
arrowContent={<span className={`${prefixCls}-arrow-content`} />}
|
||||
|
@ -106,7 +106,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@ant-design/colors": "^6.0.0",
|
||||
"@ant-design/cssinjs": "^0.0.0-alpha.40",
|
||||
"@ant-design/cssinjs": "^0.0.0-alpha.44",
|
||||
"@ant-design/icons": "^4.7.0",
|
||||
"@ant-design/react-slick": "~0.29.1",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
|
Loading…
Reference in New Issue
Block a user