Skip to content

Commit

Permalink
feat: CP support Input.TextArea allowClear、autoComplete、className、cla…
Browse files Browse the repository at this point in the history
…ssNames、style、styles (ant-design#47589)

* feat: CP support Input allowClear

* feat: CP support Input allowClear

* fix: fix

* fix: fix

* revert

* revert

* Update Input.tsx

Signed-off-by: lijianan <574980606@qq.com>

* Update getAllowClear.tsx

Signed-off-by: lijianan <574980606@qq.com>

* Update getAllowClear.tsx

Signed-off-by: lijianan <574980606@qq.com>

* test: add test case

---------

Signed-off-by: lijianan <574980606@qq.com>
  • Loading branch information
li-jia-nan authored and tanzhenyun committed Mar 29, 2024
1 parent 513444b commit 6723b8d
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 18 deletions.
2 changes: 1 addition & 1 deletion components/_util/getAllowClear.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const getAllowClear = (allowClear: AllowClear): AllowClear => {
clearIcon: <CloseCircleFilled />,
};
}

return mergedAllowClear;
};

Expand Down
56 changes: 56 additions & 0 deletions components/config-provider/__tests__/style.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ describe('ConfigProvider support style and className props', () => {
allowClear: {
clearIcon: <span className="cp-test-icon">cp-test-icon</span>,
},
autoComplete: 'test-cp-autocomplete',
}}
>
<Input
Expand All @@ -522,6 +523,61 @@ describe('ConfigProvider support style and className props', () => {
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<HTMLSpanElement>('.ant-input-affix-wrapper .cp-test-icon'),
).toBeTruthy();
});

it('Should Input.TextArea autoComplete & className & style & classNames & styles & allowClear works', () => {
const { container } = render(
<ConfigProvider
textArea={{
className: 'cp-textArea',
style: { backgroundColor: 'yellow' },
classNames: {
textarea: 'cp-classNames-textArea',
count: 'cp-classNames-count',
},
styles: {
textarea: {
color: 'blue',
},
count: {
color: 'red',
},
},
allowClear: {
clearIcon: <span className="cp-test-icon">cp-test-icon</span>,
},
autoComplete: 'test-cp-autocomplete',
}}
>
<Input.TextArea
autoComplete="test-autocomplete"
placeholder="Basic usage"
value="test"
prefix="¥"
count={{ show: true }}
/>
</ConfigProvider>,
);
const wrapperElement = container.querySelector<HTMLSpanElement>('.ant-input-affix-wrapper');
expect(wrapperElement).toHaveClass('cp-textArea');
expect(wrapperElement).toHaveStyle({ backgroundColor: 'yellow' });

const inputElement = container.querySelector<HTMLTextAreaElement>('.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<HTMLSpanElement>(
'.ant-input-affix-wrapper .ant-input-data-count',
);
expect(countElement).toHaveClass('cp-classNames-count');
expect(countElement).toHaveStyle({ color: 'red' });

expect(
container?.querySelector<HTMLSpanElement>('.ant-input-affix-wrapper .cp-test-icon'),
).toBeTruthy();
Expand Down
6 changes: 5 additions & 1 deletion components/config-provider/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -103,6 +103,9 @@ export type BadgeConfig = ComponentStyleConfig & Pick<BadgeProps, 'classNames' |
export type InputConfig = ComponentStyleConfig &
Pick<InputProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear'>;

export type TextAreaConfig = ComponentStyleConfig &
Pick<TextAreaProps, 'autoComplete' | 'classNames' | 'styles' | 'allowClear'>;

export type ButtonConfig = ComponentStyleConfig & Pick<ButtonProps, 'classNames' | 'styles'>;

export type NotificationConfig = ComponentStyleConfig & Pick<ArgsProps, 'closeIcon'>;
Expand Down Expand Up @@ -138,6 +141,7 @@ export interface ConfigConsumerProps {
csp?: CSPConfig;
autoInsertSpaceInButton?: boolean;
input?: InputConfig;
textArea?: TextAreaConfig;
pagination?: ComponentStyleConfig & Pick<PaginationProps, 'showSizeChanger'>;
locale?: Locale;
direction?: DirectionType;
Expand Down
1 change: 1 addition & 0 deletions components/config-provider/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
4 changes: 4 additions & 0 deletions components/config-provider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import type {
TableConfig,
TabsConfig,
TagConfig,
TextAreaConfig,
Theme,
ThemeConfig,
TourConfig,
Expand Down Expand Up @@ -124,6 +125,7 @@ export interface ConfigProviderProps {
form?: ComponentStyleConfig &
Pick<FormProps, 'requiredMark' | 'colon' | 'scrollToFirstError' | 'validateMessages'>;
input?: InputConfig;
textArea?: TextAreaConfig;
select?: ComponentStyleConfig & Pick<SelectProps, 'showSearch'>;
pagination?: ComponentStyleConfig & Pick<PaginationProps, 'showSizeChanger'>;
locale?: Locale;
Expand Down Expand Up @@ -321,6 +323,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
menu,
pagination,
input,
textArea,
empty,
badge,
radio,
Expand Down Expand Up @@ -405,6 +408,7 @@ const ProviderChildren: React.FC<ProviderChildrenProps> = (props) => {
steps,
image,
input,
textArea,
layout,
list,
mentions,
Expand Down
1 change: 1 addition & 0 deletions components/config-provider/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
32 changes: 16 additions & 16 deletions components/input/TextArea.tsx
Original file line number Diff line number Diff line change
@@ -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<RcTextAreaProps, 'suffix'> {
/** @deprecated Use `variant` instead */
Expand Down Expand Up @@ -52,6 +51,8 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>((props, ref) => {
classNames: classes,
rootClassName,
className,
style,
styles,
variant: customVariant,
...rest
} = props;
Expand All @@ -61,7 +62,7 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>((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);
Expand Down Expand Up @@ -91,35 +92,34 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>((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: <CloseCircleFilled /> };
}

// ===================== 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(
<RcTextArea
autoComplete={textArea?.autoComplete}
{...rest}
style={{ ...textArea?.style, ...style }}
styles={{ ...textArea?.styles, ...styles }}
disabled={mergedDisabled}
allowClear={mergedAllowClear}
className={classNames(cssVarCls, rootCls, className, rootClassName)}
className={classNames(cssVarCls, rootCls, className, rootClassName, textArea?.className)}
classNames={{
...classes,
...textArea?.classNames,
textarea: classNames(
{
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
},
hashId,
classes?.textarea,
textArea?.classNames?.textarea,
),
variant: classNames(
{
Expand Down

0 comments on commit 6723b8d

Please sign in to comment.