diff --git a/components/_util/getAllowClear.tsx b/components/_util/getAllowClear.tsx index 3bde54877f..ce487e4832 100644 --- a/components/_util/getAllowClear.tsx +++ b/components/_util/getAllowClear.tsx @@ -13,7 +13,7 @@ const getAllowClear = (allowClear: AllowClear): AllowClear => { clearIcon: , }; } - + return mergedAllowClear; }; diff --git a/components/config-provider/__tests__/style.test.tsx b/components/config-provider/__tests__/style.test.tsx index f76923f8f4..84e9c18299 100644 --- a/components/config-provider/__tests__/style.test.tsx +++ b/components/config-provider/__tests__/style.test.tsx @@ -499,6 +499,7 @@ describe('ConfigProvider support style and className props', () => { allowClear: { clearIcon: cp-test-icon, }, + autoComplete: 'test-cp-autocomplete', }} > { expect(inputElement).toHaveClass('cp-classNames-input'); expect(inputElement).toHaveStyle({ color: 'blue' }); expect(inputElement?.getAttribute('autocomplete')).toBe('test-autocomplete'); + expect(inputElement?.getAttribute('autocomplete')).not.toBe('test-cp-autocomplete'); + expect( + container?.querySelector('.ant-input-affix-wrapper .cp-test-icon'), + ).toBeTruthy(); + }); + + it('Should Input.TextArea autoComplete & className & style & classNames & styles & allowClear works', () => { + const { container } = render( + cp-test-icon, + }, + autoComplete: 'test-cp-autocomplete', + }} + > + + , + ); + const wrapperElement = container.querySelector('.ant-input-affix-wrapper'); + expect(wrapperElement).toHaveClass('cp-textArea'); + expect(wrapperElement).toHaveStyle({ backgroundColor: 'yellow' }); + + const inputElement = container.querySelector('.ant-input'); + expect(inputElement).toHaveClass('cp-classNames-textArea'); + expect(inputElement).toHaveStyle({ color: 'blue' }); + expect(inputElement?.getAttribute('autocomplete')).toBe('test-autocomplete'); + expect(inputElement?.getAttribute('autocomplete')).not.toBe('test-cp-autocomplete'); + + const countElement = container.querySelector( + '.ant-input-affix-wrapper .ant-input-data-count', + ); + expect(countElement).toHaveClass('cp-classNames-count'); + expect(countElement).toHaveStyle({ color: 'red' }); + expect( container?.querySelector('.ant-input-affix-wrapper .cp-test-icon'), ).toBeTruthy(); diff --git a/components/config-provider/context.ts b/components/config-provider/context.ts index f1b15f0d9c..1a385114b1 100644 --- a/components/config-provider/context.ts +++ b/components/config-provider/context.ts @@ -10,7 +10,7 @@ import type { CollapseProps } from '../collapse'; import type { DrawerProps } from '../drawer'; import type { FlexProps } from '../flex/interface'; import type { FormProps } from '../form/Form'; -import type { InputProps } from '../input'; +import type { InputProps, TextAreaProps } from '../input'; import type { Locale } from '../locale'; import type { MenuProps } from '../menu'; import type { ModalProps } from '../modal'; @@ -103,6 +103,9 @@ export type BadgeConfig = ComponentStyleConfig & Pick; +export type TextAreaConfig = ComponentStyleConfig & + Pick; + export type ButtonConfig = ComponentStyleConfig & Pick; export type NotificationConfig = ComponentStyleConfig & Pick; @@ -138,6 +141,7 @@ export interface ConfigConsumerProps { csp?: CSPConfig; autoInsertSpaceInButton?: boolean; input?: InputConfig; + textArea?: TextAreaConfig; pagination?: ComponentStyleConfig & Pick; locale?: Locale; direction?: DirectionType; diff --git a/components/config-provider/index.en-US.md b/components/config-provider/index.en-US.md index 77095eca55..3a0dad1b97 100644 --- a/components/config-provider/index.en-US.md +++ b/components/config-provider/index.en-US.md @@ -125,6 +125,7 @@ const { | form | Set Form common props | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0; className: 5.7.0; style: 5.7.0 | | image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, closeIcon: 5.14.0 | | input | Set Input common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 4.2.0, allowClear: 5.15.0 | +| textArea | Set TextArea common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 | | layout | Set Layout common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | list | Set List common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | menu | Set Menu common props | { className?: string, style?: React.CSSProperties, expandIcon?: ReactNode \| props => ReactNode } | - | 5.7.0, expandIcon: 5.15.0 | diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index 8803d00f1d..ee32a11222 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -39,6 +39,7 @@ import type { TableConfig, TabsConfig, TagConfig, + TextAreaConfig, Theme, ThemeConfig, TourConfig, @@ -124,6 +125,7 @@ export interface ConfigProviderProps { form?: ComponentStyleConfig & Pick; input?: InputConfig; + textArea?: TextAreaConfig; select?: ComponentStyleConfig & Pick; pagination?: ComponentStyleConfig & Pick; locale?: Locale; @@ -321,6 +323,7 @@ const ProviderChildren: React.FC = (props) => { menu, pagination, input, + textArea, empty, badge, radio, @@ -405,6 +408,7 @@ const ProviderChildren: React.FC = (props) => { steps, image, input, + textArea, layout, list, mentions, diff --git a/components/config-provider/index.zh-CN.md b/components/config-provider/index.zh-CN.md index 96aae0872a..f1671af2a5 100644 --- a/components/config-provider/index.zh-CN.md +++ b/components/config-provider/index.zh-CN.md @@ -127,6 +127,7 @@ const { | form | 设置 Form 组件的通用属性 | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), requiredMark?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | requiredMark: 4.8.0; colon: 4.18.0; scrollToFirstError: 5.2.0; className: 5.7.0; style: 5.7.0 | | image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, closeIcon: 5.14.0 | | input | 设置 Input 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.7.0, allowClear: 5.15.0 | +| textArea | 设置 TextArea 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 | | layout | 设置 Layout 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | list | 设置 List 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | menu | 设置 Menu 组件的通用属性 | { className?: string, style?: React.CSSProperties, expandIcon?: ReactNode \| props => ReactNode } | - | 5.7.0, expandIcon: 5.15.0 | diff --git a/components/input/TextArea.tsx b/components/input/TextArea.tsx index e509a7b7f2..851a86a167 100644 --- a/components/input/TextArea.tsx +++ b/components/input/TextArea.tsx @@ -1,26 +1,25 @@ import * as React from 'react'; import { forwardRef } from 'react'; -import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled'; import classNames from 'classnames'; -import type { BaseInputProps } from 'rc-input/lib/interface'; import type { TextAreaRef as RcTextAreaRef } from 'rc-textarea'; import RcTextArea from 'rc-textarea'; import type { TextAreaProps as RcTextAreaProps } from 'rc-textarea/lib/interface'; +import getAllowClear from '../_util/getAllowClear'; import type { InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils'; +import { devUseWarning } from '../_util/warning'; import { ConfigContext } from '../config-provider'; import DisabledContext from '../config-provider/DisabledContext'; +import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import useSize from '../config-provider/hooks/useSize'; import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext } from '../form/context'; +import type { Variant } from '../form/hooks/useVariants'; +import useVariant from '../form/hooks/useVariants'; import type { InputFocusOptions } from './Input'; import { triggerFocus } from './Input'; import useStyle from './style'; -import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; -import type { Variant } from '../form/hooks/useVariants'; -import useVariant from '../form/hooks/useVariants'; -import { devUseWarning } from '../_util/warning'; export interface TextAreaProps extends Omit { /** @deprecated Use `variant` instead */ @@ -52,6 +51,8 @@ const TextArea = forwardRef((props, ref) => { classNames: classes, rootClassName, className, + style, + styles, variant: customVariant, ...rest } = props; @@ -61,7 +62,7 @@ const TextArea = forwardRef((props, ref) => { deprecated(!('bordered' in props), 'bordered', 'variant'); } - const { getPrefixCls, direction } = React.useContext(ConfigContext); + const { getPrefixCls, direction, textArea } = React.useContext(ConfigContext); // ===================== Size ===================== const mergedSize = useSize(customizeSize); @@ -91,28 +92,26 @@ const TextArea = forwardRef((props, ref) => { const prefixCls = getPrefixCls('input', customizePrefixCls); - // Allow clear - let mergedAllowClear: BaseInputProps['allowClear']; - if (typeof allowClear === 'object' && allowClear?.clearIcon) { - mergedAllowClear = allowClear; - } else if (allowClear) { - mergedAllowClear = { clearIcon: }; - } - // ===================== Style ===================== const rootCls = useCSSVarCls(prefixCls); const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls); const [variant, enableVariantCls] = useVariant(customVariant, bordered); + const mergedAllowClear = getAllowClear(allowClear ?? textArea?.allowClear); + return wrapCSSVar( ((props, ref) => { }, hashId, classes?.textarea, + textArea?.classNames?.textarea, ), variant: classNames( {