-
Notifications
You must be signed in to change notification settings - Fork 2.5k
feat(TextArea): add clearable functionality to TextArea component (#7021) #7022
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
d76c2dc
bae8a1b
211b388
1674b77
5f25903
bedef31
413944a
48a98a8
c68e12d
5dfe296
d4760e3
8058a86
f83c482
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,15 @@ | ||
| import { useIsomorphicLayoutEffect } from 'ahooks' | ||
| import { CloseCircleFill } from 'antd-mobile-icons' | ||
| import type { ReactNode } from 'react' | ||
| import React, { forwardRef, useImperativeHandle, useRef } from 'react' | ||
| import runes from 'runes2' | ||
| import useInputHandleKeyDown from '../../components/input/useInputHandleKeyDown' | ||
| import { devError } from '../../utils/dev-log' | ||
| import { NativeProps, withNativeProps } from '../../utils/native-props' | ||
| import { usePropsValue } from '../../utils/use-props-value' | ||
| import { isIOS } from '../../utils/validate' | ||
| import { mergeProps } from '../../utils/with-default-props' | ||
| import { useConfig } from '../config-provider' | ||
|
|
||
| const classPrefix = 'adm-text-area' | ||
|
|
||
|
|
@@ -50,6 +53,9 @@ export type TextAreaProps = Pick< | |
| | 'previous' | ||
| | 'search' | ||
| | 'send' | ||
| clearable?: boolean | ||
| clearIcon?: ReactNode | ||
| onClear?: () => void | ||
| } & NativeProps< | ||
| | '--font-size' | ||
| | '--color' | ||
|
|
@@ -71,11 +77,13 @@ const defaultProps = { | |
| showCount: false as NonNullable<TextAreaProps['showCount']>, | ||
| autoSize: false as NonNullable<TextAreaProps['autoSize']>, | ||
| defaultValue: '', | ||
| clearIcon: <CloseCircleFill />, | ||
| } | ||
|
|
||
| export const TextArea = forwardRef<TextAreaRef, TextAreaProps>( | ||
| (p: TextAreaProps, ref) => { | ||
| const props = mergeProps(defaultProps, p) | ||
| const { locale, textArea: componentConfig = {} } = useConfig() | ||
| const props = mergeProps(defaultProps, componentConfig, p) | ||
| const { autoSize, showCount, maxLength } = props | ||
| const [value, setValue] = usePropsValue({ | ||
| ...props, | ||
|
|
@@ -137,6 +145,9 @@ export const TextArea = forwardRef<TextAreaRef, TextAreaProps>( | |
|
|
||
| const compositingRef = useRef(false) | ||
|
|
||
| const shouldShowClear = | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Input 的设计是聚焦的时候才展示清除按钮。因为在长表单的情况下,手机不同于 PC,清除按钮会过多占据视觉区域。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我曾经尝试过添加 Input 没问题是因为永远只有单行,改变输入区域宽度不影响高度。 同时也调研过淘宝、拼多多、微信的多行输入框,都是常驻。感觉我们可以在 #7021 上讨论下。
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 我的想法是可以在存在 clear 的时候提供一下边缘 padding,这样宽度就是稳定的了。因为 Input 和 TextArea 混用一个有一个没有,这个是非常古怪的。
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 嗯,明白。这个的确是比较讨厌的点。在 Input 里不用考虑换行做的动态 padding。要不然这样,如果有动态高度的,就固定 padding,反之就是动态 padding 如何?做尽可能的保全
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. longshot20260225104727_compressed.mp4调整成了 clearIcon 会根据 focus 显示消失,按照上面的讨论:
取了一个相对平衡的点,也在文档上补充说明了这种现象。 |
||
| props.clearable && !!value && !props.readOnly && !props.disabled | ||
|
|
||
| let count | ||
| const valueLength = runes(value).length | ||
| if (typeof showCount === 'function') { | ||
|
|
@@ -201,6 +212,27 @@ export const TextArea = forwardRef<TextAreaRef, TextAreaProps>( | |
| onKeyDown={handleKeydown} | ||
| enterKeyHint={props.enterKeyHint} | ||
| /> | ||
| {shouldShowClear && ( | ||
| <div | ||
| className={`${classPrefix}-clear`} | ||
| onMouseDown={e => { | ||
| e.preventDefault() | ||
| }} | ||
| onClick={() => { | ||
| setValue('') | ||
| props.onClear?.() | ||
|
|
||
| // https://github.com/ant-design/ant-design-mobile/issues/5212 | ||
| if (isIOS() && compositingRef.current) { | ||
| compositingRef.current = false | ||
| nativeTextAreaRef.current?.blur() | ||
| } | ||
| }} | ||
| aria-label={locale.TextArea.clear} | ||
| > | ||
| {props.clearIcon} | ||
| </div> | ||
| )} | ||
| {count} | ||
|
|
||
| {autoSize && ( | ||
|
|
||

Uh oh!
There was an error while loading. Please reload this page.