diff --git a/components/_util/reactNode.ts b/components/_util/reactNode.ts index 136d0f5d2f..a9c671ff69 100644 --- a/components/_util/reactNode.ts +++ b/components/_util/reactNode.ts @@ -1,8 +1,17 @@ import * as React from 'react'; -// eslint-disable-next-line import/prefer-default-export -export function cloneElement(element: React.ReactNode, ...restArgs: any[]) { - if (!React.isValidElement(element)) return element; +export const isValidElement = React.isValidElement; - return React.cloneElement(element, ...restArgs); +export function replaceElement( + element: React.ReactNode, + replacement: React.ReactNode, + props: any, +): React.ReactNode { + if (!isValidElement(element)) return replacement; + + return React.cloneElement(element, typeof props === 'function' ? props() : props); +} + +export function cloneElement(element: React.ReactNode, props?: any): React.ReactElement { + return replaceElement(element, element, props) as React.ReactElement; } diff --git a/components/alert/index.tsx b/components/alert/index.tsx index 6ae231d9bf..eabe1d76e3 100755 --- a/components/alert/index.tsx +++ b/components/alert/index.tsx @@ -15,6 +15,7 @@ import classNames from 'classnames'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import getDataOrAriaProps from '../_util/getDataOrAriaProps'; import ErrorBoundary from './ErrorBoundary'; +import { replaceElement } from '../_util/reactNode'; export interface AlertProps { /** @@ -127,15 +128,11 @@ export default class Alert extends React.Component { const { icon } = this.props; const iconType = this.getIconType(); if (icon) { - return React.isValidElement<{ className?: string }>(icon) ? ( - React.cloneElement(icon, { - className: classNames(`${prefixCls}-icon`, { - [icon.props.className as string]: icon.props.className, - }), - }) - ) : ( - {icon} - ); + return replaceElement(icon, {icon}, () => ({ + className: classNames(`${prefixCls}-icon`, { + [(icon as any).props.className]: (icon as any).props.className, + }), + })); } return React.createElement(iconType, { className: `${prefixCls}-icon` }); } diff --git a/components/auto-complete/index.tsx b/components/auto-complete/index.tsx index cbb47a4b65..e670497268 100755 --- a/components/auto-complete/index.tsx +++ b/components/auto-complete/index.tsx @@ -13,6 +13,7 @@ import omit from 'omit.js'; import Select, { InternalSelectProps, OptionType } from '../select'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import devWarning from '../_util/devWarning'; +import { isValidElement } from '../_util/reactNode'; const { Option } = Select; @@ -49,7 +50,7 @@ const AutoComplete: React.RefForwardingComponent = (p if ( childNodes.length === 1 && - React.isValidElement(childNodes[0]) && + isValidElement(childNodes[0]) && !isSelectOptionOrSelectOptGroup(childNodes[0]) ) { customizeInput = childNodes[0]; @@ -66,7 +67,7 @@ const AutoComplete: React.RefForwardingComponent = (p } else { optionChildren = dataSource ? dataSource.map(item => { - if (React.isValidElement(item)) { + if (isValidElement(item)) { return item; } switch (typeof item) { diff --git a/components/badge/ScrollNumber.tsx b/components/badge/ScrollNumber.tsx index cae853e521..0dad51c094 100644 --- a/components/badge/ScrollNumber.tsx +++ b/components/badge/ScrollNumber.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import omit from 'omit.js'; import classNames from 'classnames'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { cloneElement } from '../_util/reactNode'; function getNumberArray(num: string | number | undefined | null) { return num @@ -175,7 +176,7 @@ const ScrollNumber: React.FC = props => { }; } if (displayComponent) { - return React.cloneElement(displayComponent, { + return cloneElement(displayComponent, { className: classNames( `${prefixCls}-custom-component`, displayComponent.props && displayComponent.props.className, diff --git a/components/badge/index.tsx b/components/badge/index.tsx index 4077b16208..4c4fc21a74 100644 --- a/components/badge/index.tsx +++ b/components/badge/index.tsx @@ -6,6 +6,7 @@ import ScrollNumber from './ScrollNumber'; import { PresetColorTypes, PresetColorType, PresetStatusColorType } from '../_util/colors'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { LiteralUnion } from '../_util/type'; +import { cloneElement } from '../_util/reactNode'; export { ScrollNumberProps } from './ScrollNumber'; @@ -110,7 +111,7 @@ const Badge: React.FC = props => { if (!customNode || typeof customNode !== 'object') { return undefined; } - return React.cloneElement(customNode, { + return cloneElement(customNode, { style: { ...getStyleWithOffset(), ...(customNode.props && customNode.props.style), diff --git a/components/breadcrumb/Breadcrumb.tsx b/components/breadcrumb/Breadcrumb.tsx index 3d32e306ac..eda48cbaee 100755 --- a/components/breadcrumb/Breadcrumb.tsx +++ b/components/breadcrumb/Breadcrumb.tsx @@ -8,6 +8,7 @@ import Menu from '../menu'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import devWarning from '../_util/devWarning'; import { Omit } from '../_util/type'; +import { cloneElement } from '../_util/reactNode'; export interface Route { path: string; @@ -138,9 +139,9 @@ export default class Breadcrumb extends React.Component { "Only accepts Breadcrumb.Item and Breadcrumb.Separator as it's children", ); - return React.cloneElement(element, { + return cloneElement(element, { separator, - key: index, // eslint-disable-line react/no-array-index-key + key: index, }); }); } diff --git a/components/button/button.tsx b/components/button/button.tsx index 493fba4f8f..7c3290fbd2 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -10,6 +10,7 @@ import { Omit, tuple } from '../_util/type'; import devWarning from '../_util/devWarning'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; import LoadingIcon from './LoadingIcon'; +import { cloneElement } from '../_util/reactNode'; const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/; const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar); @@ -31,7 +32,9 @@ function insertSpace(child: React.ReactChild, needInserted: boolean) { isString(child.type) && isTwoCNChar(child.props.children) ) { - return React.cloneElement(child, {}, child.props.children.split('').join(SPACE)); + return cloneElement(child, { + children: child.props.children.split('').join(SPACE), + }); } if (typeof child === 'string') { if (isTwoCNChar(child)) { diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 0ace190eac..dd98ef9f19 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -16,6 +16,7 @@ import { ConfigConsumer, ConfigConsumerProps, RenderEmptyHandler } from '../conf import LocaleReceiver from '../locale-provider/LocaleReceiver'; import devWarning from '../_util/devWarning'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; +import { replaceElement } from '../_util/reactNode'; export interface CascaderOptionType { value?: string; @@ -554,17 +555,21 @@ class Cascader extends React.Component { dropdownMenuColumnStyle.width = this.input.input.offsetWidth; } - const inputIcon = (suffixIcon && - (React.isValidElement<{ className?: string }>(suffixIcon) ? ( - React.cloneElement(suffixIcon, { + let inputIcon: React.ReactNode; + if (suffixIcon) { + inputIcon = replaceElement( + suffixIcon, + {suffixIcon}, + () => ({ className: classNames({ - [suffixIcon.props.className!]: suffixIcon.props.className, + [(suffixIcon as any).props.className!]: (suffixIcon as any).props.className, [`${prefixCls}-picker-arrow`]: true, }), - }) - ) : ( - {suffixIcon} - ))) || ; + }), + ); + } else { + inputIcon = ; + } const input = children || ( diff --git a/components/collapse/Collapse.tsx b/components/collapse/Collapse.tsx index 7317c77aea..e9ff594546 100644 --- a/components/collapse/Collapse.tsx +++ b/components/collapse/Collapse.tsx @@ -6,6 +6,7 @@ import RightOutlined from '@ant-design/icons/RightOutlined'; import CollapsePanel from './CollapsePanel'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import animation from '../_util/openAnimation'; +import { cloneElement } from '../_util/reactNode'; export type ExpandIconPosition = 'left' | 'right' | undefined; @@ -58,11 +59,9 @@ export default class Collapse extends React.Component { )) as React.ReactNode; - return React.isValidElement(icon) - ? React.cloneElement(icon as any, { - className: classNames(icon.props.className, `${prefixCls}-arrow`), - }) - : icon; + return cloneElement(icon, () => ({ + className: classNames((icon as any).props.className, `${prefixCls}-arrow`), + })); }; renderCollapse = ({ getPrefixCls, direction }: ConfigConsumerProps) => { diff --git a/components/descriptions/index.tsx b/components/descriptions/index.tsx index 8f6e26d8f1..b65a00a22d 100644 --- a/components/descriptions/index.tsx +++ b/components/descriptions/index.tsx @@ -11,6 +11,7 @@ import devWarning from '../_util/devWarning'; import { ConfigContext } from '../config-provider'; import Row from './Row'; import DescriptionsItem from './Item'; +import { cloneElement } from '../_util/reactNode'; const DEFAULT_COLUMN_MAP: Record = { xxl: 3, @@ -46,7 +47,7 @@ function getFilledItem( let clone = node; if (span === undefined || span > rowRestCol) { - clone = React.cloneElement(node, { + clone = cloneElement(node, { span: rowRestCol, }); devWarning( diff --git a/components/dropdown/dropdown.tsx b/components/dropdown/dropdown.tsx index 28436ac0a0..2ef308ba7f 100644 --- a/components/dropdown/dropdown.tsx +++ b/components/dropdown/dropdown.tsx @@ -7,6 +7,7 @@ import DropdownButton from './dropdown-button'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import devWarning from '../_util/devWarning'; import { tuple } from '../_util/type'; +import { cloneElement } from '../_util/reactNode'; const Placements = tuple( 'topLeft', @@ -107,7 +108,7 @@ export default class Dropdown extends React.Component { const fixedModeOverlay = typeof overlayNode.type === 'string' ? overlay - : React.cloneElement(overlayNode, { + : cloneElement(overlayNode, { mode: 'vertical', selectable, focusable, @@ -142,7 +143,7 @@ export default class Dropdown extends React.Component { const prefixCls = getPrefixCls('dropdown', customizePrefixCls); const child = React.Children.only(children) as React.ReactElement; - const dropdownTrigger = React.cloneElement(child, { + const dropdownTrigger = cloneElement(child, { className: classNames(child.props.className, `${prefixCls}-trigger`, { [`${prefixCls}-rtl`]: direction === 'rtl', }), diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx index b1c6280e51..b4807c176d 100644 --- a/components/form/FormItem.tsx +++ b/components/form/FormItem.tsx @@ -13,6 +13,7 @@ import FormItemLabel, { FormItemLabelProps } from './FormItemLabel'; import FormItemInput, { FormItemInputProps } from './FormItemInput'; import { FormContext, FormItemContext } from './context'; import { toArray, getFieldId, useFrameState } from './util'; +import { cloneElement, isValidElement } from '../_util/reactNode'; const ValidateStatuses = tuple('success', 'warning', 'error', 'validating', ''); export type ValidateStatus = typeof ValidateStatuses[number]; @@ -306,7 +307,7 @@ function FormItem(props: FormItemProps): React.ReactElement { 'Form.Item', 'Must set `name` or use render props when `dependencies` is set.', ); - } else if (React.isValidElement(children)) { + } else if (isValidElement(children)) { devWarning( children.props.defaultValue === undefined, 'Form.Item', @@ -330,7 +331,7 @@ function FormItem(props: FormItemProps): React.ReactElement { value={mergedControl[props.valuePropName || 'value']} update={updateRef.current} > - {React.cloneElement(children, childProps)} + {cloneElement(children, childProps)} ); } else if (isRenderProps && shouldUpdate && !hasName) { diff --git a/components/input/ClearableLabeledInput.tsx b/components/input/ClearableLabeledInput.tsx index c8ef9f8ac2..a13c53e9f4 100644 --- a/components/input/ClearableLabeledInput.tsx +++ b/components/input/ClearableLabeledInput.tsx @@ -4,6 +4,7 @@ import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled'; import { tuple } from '../_util/type'; import { InputProps, getInputClassName } from './Input'; import { SizeType } from '../config-provider/SizeContext'; +import { cloneElement } from '../_util/reactNode'; const ClearableInputType = tuple('text', 'input'); @@ -103,7 +104,7 @@ class ClearableLabeledInput extends React.Component { } = this.props; const suffixNode = this.renderSuffix(prefixCls); if (!hasPrefixSuffix(this.props)) { - return React.cloneElement(element, { + return cloneElement(element, { value, }); } @@ -126,7 +127,7 @@ class ClearableLabeledInput extends React.Component { onMouseUp={this.onInputMouseUp} > {prefixNode} - {React.cloneElement(element, { + {cloneElement(element, { style: null, value, className: getInputClassName(prefixCls, size, disabled), @@ -167,7 +168,7 @@ class ClearableLabeledInput extends React.Component { {addonBeforeNode} - {React.cloneElement(labeledElement, { style: null })} + {cloneElement(labeledElement, { style: null })} {addonAfterNode} @@ -177,7 +178,7 @@ class ClearableLabeledInput extends React.Component { renderTextAreaWithClearIcon(prefixCls: string, element: React.ReactElement) { const { value, allowClear, className, style, direction } = this.props; if (!allowClear) { - return React.cloneElement(element, { + return cloneElement(element, { value, }); } @@ -189,7 +190,7 @@ class ClearableLabeledInput extends React.Component { ); return ( - {React.cloneElement(element, { + {cloneElement(element, { style: null, value, })} diff --git a/components/input/Search.tsx b/components/input/Search.tsx index f9532c0eed..84e4f5d347 100644 --- a/components/input/Search.tsx +++ b/components/input/Search.tsx @@ -6,6 +6,7 @@ import Input, { InputProps } from './Input'; import Button from '../button'; import SizeContext, { SizeType } from '../config-provider/SizeContext'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { replaceElement, cloneElement } from '../_util/reactNode'; export interface SearchProps extends InputProps { inputPrefixCls?: string; @@ -97,11 +98,9 @@ export default class Search extends React.Component { if (suffix) { return [ - React.isValidElement(suffix) - ? React.cloneElement(suffix, { - key: 'suffix', - }) - : null, + replaceElement(suffix, null, { + key: 'suffix', + }), icon, ]; } @@ -125,7 +124,7 @@ export default class Search extends React.Component { enterButtonAsElement.type && (enterButtonAsElement.type as typeof Button).__ANT_BUTTON === true; if (isAntdButton || enterButtonAsElement.type === 'button') { - button = React.cloneElement(enterButtonAsElement, { + button = cloneElement(enterButtonAsElement, { onMouseDown: this.onMouseDown, onClick: this.onSearch, key: 'enterButton', @@ -155,11 +154,9 @@ export default class Search extends React.Component { if (addonAfter) { return [ button, - React.isValidElement(addonAfter) - ? React.cloneElement(addonAfter, { - key: 'addonAfter', - }) - : null, + replaceElement(addonAfter, null, { + key: 'addonAfter', + }), ]; } diff --git a/components/list/index.tsx b/components/list/index.tsx index 8ad8c3b121..2e85481c33 100644 --- a/components/list/index.tsx +++ b/components/list/index.tsx @@ -8,6 +8,7 @@ import { RenderEmptyHandler, ConfigContext } from '../config-provider'; import Pagination, { PaginationConfig } from '../pagination'; import { Row } from '../grid'; import Item from './Item'; +import { cloneElement } from '../_util/reactNode'; export { ListItemProps, ListItemMetaProps } from './Item'; @@ -247,7 +248,7 @@ function List({ pagination, ...props }: ListProps) { if (splitDataSource.length > 0) { const items = splitDataSource.map((item: any, index: number) => renderItem(item, index)); const childrenList = React.Children.map(items, (child: any, index) => - React.cloneElement(child, { + cloneElement(child, { key: keys[index], colStyle, }), diff --git a/components/menu/MenuItem.tsx b/components/menu/MenuItem.tsx index 89038863ca..72e7b804ae 100644 --- a/components/menu/MenuItem.tsx +++ b/components/menu/MenuItem.tsx @@ -6,6 +6,7 @@ import { ClickParam } from '.'; import MenuContext, { MenuContextProps } from './MenuContext'; import Tooltip, { TooltipProps } from '../tooltip'; import { SiderContext, SiderContextProps } from '../layout/Sider'; +import { isValidElement } from '../_util/reactNode'; export interface MenuItemProps extends Omit< @@ -43,7 +44,7 @@ export default class MenuItem extends React.Component { const { icon, children } = this.props; // inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span // ref: https://github.com/ant-design/ant-design/pull/23456 - if (!icon || (React.isValidElement(children) && children.type === 'span')) { + if (!icon || (isValidElement(children) && children.type === 'span')) { return children; } return {children}; diff --git a/components/menu/SubMenu.tsx b/components/menu/SubMenu.tsx index 3b2d006e80..dd4f1cd152 100644 --- a/components/menu/SubMenu.tsx +++ b/components/menu/SubMenu.tsx @@ -4,6 +4,7 @@ import { SubMenu as RcSubMenu } from 'rc-menu'; import classNames from 'classnames'; import omit from 'omit.js'; import MenuContext, { MenuContextProps } from './MenuContext'; +import { isValidElement } from '../_util/reactNode'; interface TitleEventEntity { key: string; @@ -49,7 +50,7 @@ class SubMenu extends React.Component { } // inline-collapsed.md demo 依赖 span 来隐藏文字,有 icon 属性,则内部包裹一个 span // ref: https://github.com/ant-design/ant-design/pull/23456 - const titleIsSpan = React.isValidElement(title) && title.type === 'span'; + const titleIsSpan = isValidElement(title) && title.type === 'span'; return ( <> {icon} diff --git a/components/spin/index.tsx b/components/spin/index.tsx index 99f57063b4..7e2d16d4f8 100644 --- a/components/spin/index.tsx +++ b/components/spin/index.tsx @@ -4,6 +4,7 @@ import omit from 'omit.js'; import debounce from 'lodash/debounce'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { tuple } from '../_util/type'; +import { isValidElement, cloneElement } from '../_util/reactNode'; const SpinSizes = tuple('small', 'default', 'large'); export type SpinSize = typeof SpinSizes[number]; @@ -38,14 +39,14 @@ function renderIndicator(prefixCls: string, props: SpinProps): React.ReactNode { return null; } - if (React.isValidElement(indicator)) { - return React.cloneElement(indicator, { + if (isValidElement(indicator)) { + return cloneElement(indicator, { className: classNames(indicator.props.className, dotClassName), }); } - if (React.isValidElement(defaultIndicator)) { - return React.cloneElement(defaultIndicator as SpinIndicator, { + if (isValidElement(defaultIndicator)) { + return cloneElement(defaultIndicator as SpinIndicator, { className: classNames((defaultIndicator as SpinIndicator).props.className, dotClassName), }); } diff --git a/components/statistic/Countdown.tsx b/components/statistic/Countdown.tsx index c74e8b7a7f..e008bf5496 100644 --- a/components/statistic/Countdown.tsx +++ b/components/statistic/Countdown.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import Statistic, { StatisticProps } from './Statistic'; import { formatCountdown, countdownValueType, FormatConfig } from './utils'; +import { cloneElement } from '../_util/reactNode'; const REFRESH_INTERVAL = 1000 / 30; @@ -72,7 +73,7 @@ class Countdown extends React.Component { // Countdown do not need display the timestamp valueRender = (node: React.ReactElement) => - React.cloneElement(node, { + cloneElement(node, { title: undefined, }); diff --git a/components/tabs/TabBar.tsx b/components/tabs/TabBar.tsx index 27a93aebc0..379b3ee890 100644 --- a/components/tabs/TabBar.tsx +++ b/components/tabs/TabBar.tsx @@ -8,6 +8,7 @@ import RightOutlined from '@ant-design/icons/RightOutlined'; import { TabsProps } from './index'; import { ConfigConsumerProps, ConfigConsumer } from '../config-provider'; +import { cloneElement } from '../_util/reactNode'; export default class TabBar extends React.Component { static defaultProps = { @@ -81,7 +82,7 @@ export default class TabBar extends React.Component { RenderTabBar = ; } - return React.cloneElement(RenderTabBar); + return cloneElement(RenderTabBar); }; render() { diff --git a/components/tabs/index.tsx b/components/tabs/index.tsx index 4a1184d865..b52fae8a3b 100755 --- a/components/tabs/index.tsx +++ b/components/tabs/index.tsx @@ -10,6 +10,7 @@ import TabBar from './TabBar'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; import { isFlexSupported } from '../_util/styleChecker'; +import { cloneElement, isValidElement } from '../_util/reactNode'; export type TabsType = 'line' | 'card' | 'editable-card'; export type TabsPosition = 'top' | 'right' | 'bottom' | 'left'; @@ -129,7 +130,7 @@ export default class Tabs extends React.Component { if (type === 'editable-card') { childrenWithClose = []; React.Children.forEach(children as React.ReactNode, (child, index) => { - if (!React.isValidElement(child)) return child; + if (!isValidElement(child)) return child; let { closable } = child.props; const { closeIcon: customCloseIcon } = child.props; closable = typeof closable === 'undefined' ? true : closable; @@ -146,7 +147,7 @@ export default class Tabs extends React.Component { ); const closeIcon = closable ? customIcon : null; childrenWithClose.push( - React.cloneElement(child, { + cloneElement(child, { tab: (
{child.props.tab} diff --git a/components/timeline/Timeline.tsx b/components/timeline/Timeline.tsx index 156ac9537b..38419a1fa0 100644 --- a/components/timeline/Timeline.tsx +++ b/components/timeline/Timeline.tsx @@ -4,6 +4,7 @@ import LoadingOutlined from '@ant-design/icons/LoadingOutlined'; import TimelineItem, { TimeLineItemProps } from './TimelineItem'; import { ConfigContext } from '../config-provider'; +import { cloneElement } from '../_util/reactNode'; export interface TimelineProps { prefixCls?: string; @@ -64,7 +65,7 @@ const Timeline: TimelineType = props => { const items = React.Children.map(truthyItems, (ele: React.ReactElement, idx) => { const pendingClass = idx === itemsCount - 2 ? lastCls : ''; const readyClass = idx === itemsCount - 1 ? lastCls : ''; - return React.cloneElement(ele, { + return cloneElement(ele, { className: classNames([ ele.props.className, !reverse && !!pending ? pendingClass : readyClass, diff --git a/components/tooltip/index.tsx b/components/tooltip/index.tsx index dd27399c5c..55bcdc8db3 100644 --- a/components/tooltip/index.tsx +++ b/components/tooltip/index.tsx @@ -5,6 +5,7 @@ import classNames from 'classnames'; import { BuildInPlacements } from 'rc-trigger/lib/interface'; import getPlacements, { AdjustOverflow, PlacementsConfig } from './placements'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { cloneElement, isValidElement } from '../_util/reactNode'; export { AdjustOverflow, PlacementsConfig }; @@ -105,7 +106,7 @@ function getDisabledCompatibleChildren(element: React.ReactElement, prefixC ...omitted, pointerEvents: 'none', }; - const child = React.cloneElement(element, { + const child = cloneElement(element, { style: buttonStyle, className: null, }); @@ -243,7 +244,7 @@ class Tooltip extends React.Component { } const child = getDisabledCompatibleChildren( - React.isValidElement(children) ? children : {children}, + isValidElement(children) ? children : {children}, prefixCls, ); @@ -268,7 +269,7 @@ class Tooltip extends React.Component { onVisibleChange={this.onVisibleChange} onPopupAlign={this.onPopupAlign} > - {visible ? React.cloneElement(child, { className: childCls }) : child} + {visible ? cloneElement(child, { className: childCls }) : child} ); }; diff --git a/components/transfer/list.tsx b/components/transfer/list.tsx index e89708ff08..b5a1e8084d 100644 --- a/components/transfer/list.tsx +++ b/components/transfer/list.tsx @@ -16,13 +16,14 @@ import { import Search from './search'; import DefaultListBody, { TransferListBodyProps, OmitProps } from './ListBody'; import { PaginationType } from './interface'; +import { isValidElement } from '../_util/reactNode'; const defaultRender = () => null; function isRenderResultPlainObject(result: RenderResult) { return ( result && - !React.isValidElement(result) && + !isValidElement(result) && Object.prototype.toString.call(result) === '[object Object]' ); } diff --git a/components/tree/utils/iconUtil.tsx b/components/tree/utils/iconUtil.tsx index 794ee02a49..9695e78cf6 100644 --- a/components/tree/utils/iconUtil.tsx +++ b/components/tree/utils/iconUtil.tsx @@ -6,6 +6,7 @@ import MinusSquareOutlined from '@ant-design/icons/MinusSquareOutlined'; import PlusSquareOutlined from '@ant-design/icons/PlusSquareOutlined'; import CaretDownFilled from '@ant-design/icons/CaretDownFilled'; import { AntTreeNodeProps } from '../Tree'; +import { isValidElement, cloneElement } from '../../_util/reactNode'; export default function renderSwitcherIcon( prefixCls: string, @@ -20,8 +21,8 @@ export default function renderSwitcherIcon( return showLine ? : null; } const switcherCls = `${prefixCls}-switcher-icon`; - if (React.isValidElement(switcherIcon)) { - return React.cloneElement(switcherIcon, { + if (isValidElement(switcherIcon)) { + return cloneElement(switcherIcon, { className: classNames(switcherIcon.props.className || '', switcherCls), }); } diff --git a/components/upload/UploadList.tsx b/components/upload/UploadList.tsx index 5256257b03..325ea0aaac 100644 --- a/components/upload/UploadList.tsx +++ b/components/upload/UploadList.tsx @@ -14,6 +14,7 @@ import { previewImage, isImageUrl } from './utils'; import Tooltip from '../tooltip'; import Progress from '../progress'; import { ConfigConsumer, ConfigConsumerProps } from '../config-provider'; +import { cloneElement, isValidElement } from '../_util/reactNode'; export default class UploadList extends React.Component { static defaultProps = { @@ -98,8 +99,8 @@ export default class UploadList extends React.Component { }; handleActionIconRender = (customIcon: React.ReactNode, callback: () => void, title?: string) => { - if (React.isValidElement(customIcon)) { - return React.cloneElement(customIcon, { + if (isValidElement(customIcon)) { + return cloneElement(customIcon, { ...customIcon.props, title, onClick: (e: React.MouseEvent) => { diff --git a/webpack.config.js b/webpack.config.js index ff6ea1636e..cd1f49c27c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -56,7 +56,6 @@ function processWebpackThemeConfig(themeConfig, theme, vars) { themeConfig.forEach(config => { ignoreMomentLocale(config); externalMoment(config); - injectWarningCondition(config); // rename default entry to ${theme} entry Object.keys(config.entry).forEach(entryName => { @@ -87,6 +86,10 @@ const webpackConfig = getWebpackConfig(false); const webpackDarkConfig = getWebpackConfig(false); const webpackCompactConfig = getWebpackConfig(false); +webpackConfig.forEach(config => { + injectWarningCondition(config); +}); + if (process.env.RUN_ENV === 'PRODUCTION') { webpackConfig.forEach(config => { ignoreMomentLocale(config);