From 08207d0cb9653948fe4e76b8ae113ea011c5ef88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=AB=98=E8=89=B3=E5=85=B5?= Date: Thu, 3 Sep 2026 08:43:23 +0800 Subject: [PATCH] refactor: use renderable guards --- package.json | 2 +- src/PickerInput/Popup/Footer.tsx | 7 ++++-- src/PickerInput/Selector/Icon.tsx | 3 ++- src/PickerInput/Selector/RangeSelector.tsx | 7 +++--- .../Selector/SingleSelector/index.tsx | 5 +++-- .../Selector/hooks/useClearIcon.tsx | 10 ++++++--- src/PickerPanel/PanelBody.tsx | 3 ++- .../TimePanel/TimePanelBody/index.tsx | 9 ++++---- src/utils/getClearIcon.tsx | 22 ++++++++++--------- 9 files changed, 40 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 2cdd25634..ac0f27d79 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "@rc-component/overflow": "^1.0.0", "@rc-component/resize-observer": "^1.0.0", "@rc-component/trigger": "^3.6.15", - "@rc-component/util": "^1.11.1", + "@rc-component/util": "^1.13.0", "clsx": "^2.1.1" }, "devDependencies": { diff --git a/src/PickerInput/Popup/Footer.tsx b/src/PickerInput/Popup/Footer.tsx index ba15dba3d..85f1603b0 100644 --- a/src/PickerInput/Popup/Footer.tsx +++ b/src/PickerInput/Popup/Footer.tsx @@ -1,4 +1,5 @@ import { clsx } from 'clsx'; +import { isReactRenderable } from '@rc-component/util'; import * as React from 'react'; import type { GenerateConfig } from '../../generate'; import useTimeInfo from '../../hooks/useTimeInfo'; @@ -102,7 +103,7 @@ export default function Footer(props: FooterProps) { ); // ======================== Render ======================== - if (!extraNode && !rangeNode) { + if (!isReactRenderable(extraNode) && !isReactRenderable(rangeNode)) { return null; } @@ -111,7 +112,9 @@ export default function Footer(props: FooterProps) { className={clsx(`${prefixCls}-footer`, classNames.popup.footer)} style={styles.popup.footer} > - {extraNode &&
{extraNode}
} + {isReactRenderable(extraNode) && ( +
{extraNode}
+ )} {rangeNode} ); diff --git a/src/PickerInput/Selector/Icon.tsx b/src/PickerInput/Selector/Icon.tsx index c5090060e..4fdaacee1 100644 --- a/src/PickerInput/Selector/Icon.tsx +++ b/src/PickerInput/Selector/Icon.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { isReactRenderable } from '@rc-component/util'; import PickerContext from '../context'; import { clsx } from 'clsx'; @@ -9,7 +10,7 @@ export interface IconProps extends React.HtmlHTMLAttributes { export default function Icon({ icon, ...restProps }: IconProps) { const { prefixCls, classNames, styles } = React.useContext(PickerContext); - return icon ? ( + return isReactRenderable(icon) ? ( ( }, [activeIndex]); // ======================== Clear ========================= - const showClear = clearIcon && ((value[0] && !disabled[0]) || (value[1] && !disabled[1])); + const showClear = + isReactRenderable(clearIcon) && ((value[0] && !disabled[0]) || (value[1] && !disabled[1])); // ======================= Disabled ======================= const startAutoFocus = autoFocus && !disabled[0]; @@ -246,7 +247,7 @@ function RangeSelector( onMouseDown?.(e); }} > - {prefix && ( + {isReactRenderable(prefix) && (
{prefix}
diff --git a/src/PickerInput/Selector/SingleSelector/index.tsx b/src/PickerInput/Selector/SingleSelector/index.tsx index c2d7c61b2..886681b20 100644 --- a/src/PickerInput/Selector/SingleSelector/index.tsx +++ b/src/PickerInput/Selector/SingleSelector/index.tsx @@ -1,4 +1,5 @@ import { clsx } from 'clsx'; +import { isReactRenderable } from '@rc-component/util'; import * as React from 'react'; import type { InternalMode, PickerRef, SelectorProps } from '../../../interface'; import { isSame } from '../../../utils/dateUtil'; @@ -159,7 +160,7 @@ function SingleSelector( ); // ======================== Clear ========================= - const showClear = !!(clearIcon && value.length && !disabled); + const showClear = isReactRenderable(clearIcon) && Boolean(value.length) && !disabled; // ======================= Multiple ======================= const selectorNode = multiple ? ( @@ -226,7 +227,7 @@ function SingleSelector( onMouseDown?.(e); }} > - {prefix && ( + {isReactRenderable(prefix) && (
{prefix}
diff --git a/src/PickerInput/Selector/hooks/useClearIcon.tsx b/src/PickerInput/Selector/hooks/useClearIcon.tsx index 37c587fe9..d9bcd1131 100644 --- a/src/PickerInput/Selector/hooks/useClearIcon.tsx +++ b/src/PickerInput/Selector/hooks/useClearIcon.tsx @@ -1,4 +1,4 @@ -import { warning } from '@rc-component/util'; +import { isReactRenderable, warning } from '@rc-component/util'; import type { ReactNode } from 'react'; import * as React from 'react'; @@ -10,7 +10,7 @@ export function fillClearIcon( allowClear?: boolean | { clearIcon?: ReactNode }, clearIcon?: ReactNode, ) { - if (process.env.NODE_ENV !== 'production' && clearIcon) { + if (process.env.NODE_ENV !== 'production' && isReactRenderable(clearIcon)) { warning(false, '`clearIcon` will be removed in future. Please use `allowClear` instead.'); } @@ -20,5 +20,9 @@ export function fillClearIcon( const config = allowClear && typeof allowClear === 'object' ? allowClear : {}; - return config.clearIcon || clearIcon || ; + if (isReactRenderable(config.clearIcon)) { + return config.clearIcon; + } + + return isReactRenderable(clearIcon) ? clearIcon : ; } diff --git a/src/PickerPanel/PanelBody.tsx b/src/PickerPanel/PanelBody.tsx index 34b6fe011..17f3f0819 100644 --- a/src/PickerPanel/PanelBody.tsx +++ b/src/PickerPanel/PanelBody.tsx @@ -1,4 +1,5 @@ import { clsx } from 'clsx'; +import { isNonNullable } from '@rc-component/util'; import * as React from 'react'; import type { DisabledDate } from '../interface'; import { formatValue, isInRange, isSame } from '../utils/dateUtil'; @@ -186,7 +187,7 @@ export default function PanelBody(props: PanelBod return (
- {headerCells && ( + {isNonNullable(headerCells) && ( {headerCells} diff --git a/src/PickerPanel/TimePanel/TimePanelBody/index.tsx b/src/PickerPanel/TimePanel/TimePanelBody/index.tsx index c389c5716..84aae5d64 100644 --- a/src/PickerPanel/TimePanel/TimePanelBody/index.tsx +++ b/src/PickerPanel/TimePanel/TimePanelBody/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { isNonNullable } from '@rc-component/util'; import useTimeInfo from '../../../hooks/useTimeInfo'; import type { SharedPanelProps, SharedTimeProps } from '../../../interface'; import { formatValue } from '../../../utils/dateUtil'; @@ -157,19 +158,17 @@ export default function TimePanelBody( const triggerDateTmpl = React.useMemo(() => { let tmpl = value || pickerValue || generateConfig.getNow(); - const isNotNull = (num: number) => num !== null && num !== undefined; - - if (isNotNull(hour)) { + if (isNonNullable(hour)) { tmpl = generateConfig.setHour(tmpl, hour); tmpl = generateConfig.setMinute(tmpl, minute); tmpl = generateConfig.setSecond(tmpl, second); tmpl = generateConfig.setMillisecond(tmpl, millisecond); - } else if (isNotNull(pickerHour)) { + } else if (isNonNullable(pickerHour)) { tmpl = generateConfig.setHour(tmpl, pickerHour); tmpl = generateConfig.setMinute(tmpl, pickerMinute); tmpl = generateConfig.setSecond(tmpl, pickerSecond); tmpl = generateConfig.setMillisecond(tmpl, pickerMillisecond); - } else if (isNotNull(validHour)) { + } else if (isNonNullable(validHour)) { tmpl = generateConfig.setHour(tmpl, validHour); tmpl = generateConfig.setMinute(tmpl, validMinute); tmpl = generateConfig.setSecond(tmpl, validSecond); diff --git a/src/utils/getClearIcon.tsx b/src/utils/getClearIcon.tsx index 4769abb3e..3e31bdc63 100644 --- a/src/utils/getClearIcon.tsx +++ b/src/utils/getClearIcon.tsx @@ -1,15 +1,17 @@ -import type { ReactNode } from "react"; -import React from "react"; +import type { ReactNode } from 'react'; +import React from 'react'; +import { isReactRenderable } from '@rc-component/util'; export function getClearIcon( - prefixCls: string, - allowClear?: boolean | { clearIcon?: ReactNode }, - clearIcon?: ReactNode, + prefixCls: string, + allowClear?: boolean | { clearIcon?: ReactNode }, + clearIcon?: ReactNode, ) { + const mergedClearIcon = typeof allowClear === 'object' ? allowClear.clearIcon : clearIcon; - const mergedClearIcon = typeof allowClear === "object" ? allowClear.clearIcon : clearIcon; - - return ( - mergedClearIcon || - ); + return isReactRenderable(mergedClearIcon) ? ( + mergedClearIcon + ) : ( + + ); }