diff --git a/README.md b/README.md index 1ed89cf..cf13115 100644 --- a/README.md +++ b/README.md @@ -58,50 +58,50 @@ Then open `http://localhost:8000`. ### Input -| Property | Type | Default | Description | -| ------------ | ---------------------------------------------------------- | ---------- | --------------------------------------------------------------- | -| addonAfter | `ReactNode` | - | Element displayed after the input. | -| addonBefore | `ReactNode` | - | Element displayed before the input. | -| allowClear | `boolean \| { disabled?: boolean; clearIcon?: ReactNode }` | `false` | Show a clear button for the current value. | -| className | `string` | - | Class name for the input element. | -| classNames | `InputProps['classNames']` | - | Semantic class names for input slots. | -| count | `CountConfig` | - | Custom count strategy, limit, visibility, and exceed formatter. | -| defaultValue | `string \| number \| readonly string[] \| bigint` | - | Initial input value. | -| disabled | `boolean` | `false` | Disable the input. | -| htmlSize | `number` | - | Native input `size` attribute. | -| maxLength | `number` | - | Native input `maxLength` attribute. | -| prefix | `ReactNode` | - | Prefix content inside the input wrapper. | -| prefixCls | `string` | `rc-input` | Class name prefix. | -| showCount | `boolean \| { formatter: ShowCountFormatter }` | `false` | Show character count. Prefer `count.show` for new code. | -| styles | `InputProps['styles']` | - | Semantic styles for input slots. | -| suffix | `ReactNode` | - | Suffix content inside the input wrapper. | -| type | `InputProps['type']` | `text` | Native input type. Use `TextArea` for textarea behavior. | -| value | `string \| number \| readonly string[] \| bigint` | - | Controlled input value. | -| onChange | `React.ChangeEventHandler` | - | Triggered when the value changes. | -| onClear | `() => void` | - | Triggered when the clear button is clicked. | -| onPressEnter | `React.KeyboardEventHandler` | - | Triggered when Enter is pressed. | +| Property | Type | Default | Description | +| ------------ | ----------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------- | +| addonAfter | `ReactNode` | - | Element displayed after the input. | +| addonBefore | `ReactNode` | - | Element displayed before the input. | +| allowClear | `boolean \| { disabled?: boolean; clearIcon?: ReactNode; tabIndex?: number }` | `false` | Show a clear button for the current value. Set `tabIndex: -1` to skip it during Tab navigation. | +| className | `string` | - | Class name for the input element. | +| classNames | `InputProps['classNames']` | - | Semantic class names for input slots. | +| count | `CountConfig` | - | Custom count strategy, limit, visibility, and exceed formatter. | +| defaultValue | `string \| number \| readonly string[] \| bigint` | - | Initial input value. | +| disabled | `boolean` | `false` | Disable the input. | +| htmlSize | `number` | - | Native input `size` attribute. | +| maxLength | `number` | - | Native input `maxLength` attribute. | +| prefix | `ReactNode` | - | Prefix content inside the input wrapper. | +| prefixCls | `string` | `rc-input` | Class name prefix. | +| showCount | `boolean \| { formatter: ShowCountFormatter }` | `false` | Show character count. Prefer `count.show` for new code. | +| styles | `InputProps['styles']` | - | Semantic styles for input slots. | +| suffix | `ReactNode` | - | Suffix content inside the input wrapper. | +| type | `InputProps['type']` | `text` | Native input type. Use `TextArea` for textarea behavior. | +| value | `string \| number \| readonly string[] \| bigint` | - | Controlled input value. | +| onChange | `React.ChangeEventHandler` | - | Triggered when the value changes. | +| onClear | `() => void` | - | Triggered when the clear button is clicked. | +| onPressEnter | `React.KeyboardEventHandler` | - | Triggered when Enter is pressed. | ### TextArea -| Property | Type | Default | Description | -| ------------ | ---------------------------------------------------------- | ------------- | --------------------------------------------------------------- | -| allowClear | `boolean \| { disabled?: boolean; clearIcon?: ReactNode }` | `false` | Show a clear button for the current value. | -| autoSize | `boolean \| { minRows?: number; maxRows?: number }` | `false` | Auto resize height by content. | -| className | `string` | - | Class name for the textarea. | -| classNames | `TextAreaProps['classNames']` | - | Semantic class names for textarea slots. | -| count | `CountConfig` | - | Custom count strategy, limit, visibility, and exceed formatter. | -| defaultValue | `string \| number \| readonly string[] \| bigint` | - | Initial textarea value. | -| maxLength | `number` | - | Native textarea `maxLength` attribute. | -| prefixCls | `string` | `rc-textarea` | Class name prefix. | -| showCount | `boolean \| { formatter: ShowCountFormatter }` | `false` | Show character count. Prefer `count.show` for new code. | -| style | `React.CSSProperties` | - | Inline styles for the textarea. | -| styles | `TextAreaProps['styles']` | - | Semantic styles for textarea slots. | -| suffix | `ReactNode` | - | Suffix content inside the textarea wrapper. | -| value | `string \| number \| readonly string[] \| bigint` | - | Controlled textarea value. | -| onChange | `React.ChangeEventHandler` | - | Triggered when the value changes. | -| onClear | `() => void` | - | Triggered when the clear button is clicked. | -| onPressEnter | `React.KeyboardEventHandler` | - | Triggered when Enter is pressed. | -| onResize | `(size: { width: number; height: number }) => void` | - | Triggered when textarea size changes. | +| Property | Type | Default | Description | +| ------------ | ----------------------------------------------------------------------------- | ------------- | ----------------------------------------------------------------------------------------------- | +| allowClear | `boolean \| { disabled?: boolean; clearIcon?: ReactNode; tabIndex?: number }` | `false` | Show a clear button for the current value. Set `tabIndex: -1` to skip it during Tab navigation. | +| autoSize | `boolean \| { minRows?: number; maxRows?: number }` | `false` | Auto resize height by content. | +| className | `string` | - | Class name for the textarea. | +| classNames | `TextAreaProps['classNames']` | - | Semantic class names for textarea slots. | +| count | `CountConfig` | - | Custom count strategy, limit, visibility, and exceed formatter. | +| defaultValue | `string \| number \| readonly string[] \| bigint` | - | Initial textarea value. | +| maxLength | `number` | - | Native textarea `maxLength` attribute. | +| prefixCls | `string` | `rc-textarea` | Class name prefix. | +| showCount | `boolean \| { formatter: ShowCountFormatter }` | `false` | Show character count. Prefer `count.show` for new code. | +| style | `React.CSSProperties` | - | Inline styles for the textarea. | +| styles | `TextAreaProps['styles']` | - | Semantic styles for textarea slots. | +| suffix | `ReactNode` | - | Suffix content inside the textarea wrapper. | +| value | `string \| number \| readonly string[] \| bigint` | - | Controlled textarea value. | +| onChange | `React.ChangeEventHandler` | - | Triggered when the value changes. | +| onClear | `() => void` | - | Triggered when the clear button is clicked. | +| onPressEnter | `React.KeyboardEventHandler` | - | Triggered when Enter is pressed. | +| onResize | `(size: { width: number; height: number }) => void` | - | Triggered when textarea size changes. | ### Refs diff --git a/src/BaseInput.tsx b/src/BaseInput.tsx index 29d309b..eebfa73 100644 --- a/src/BaseInput.tsx +++ b/src/BaseInput.tsx @@ -2,6 +2,7 @@ import { clsx } from 'clsx'; import { isReactRenderable } from '@rc-component/util'; import type { ReactElement, ReactNode } from 'react'; import React, { cloneElement, useRef } from 'react'; +import useAllowClear from './hooks/useAllowClear'; import type { BaseInputProps } from './interface'; import { hasAddon, hasPrefixSuffix } from './utils/commonUtils'; @@ -37,6 +38,7 @@ const BaseInput = React.forwardRef((props, ref) => { onClear, } = props; + const [showAllowClear, allowClearConfig] = useAllowClear(allowClear); const inputElement = children ?? inputEl; const AffixWrapperComponent = components?.affixWrapper || 'span'; @@ -74,22 +76,18 @@ const BaseInput = React.forwardRef((props, ref) => { if (hasAffix) { // ================== Clear Icon ================== // let clearIcon: ReactNode = null; - if (allowClear) { + if (showAllowClear) { const needClear = - !disabled && - !readOnly && - value && - !(typeof allowClear === 'object' && allowClear.disabled); + !disabled && !readOnly && value && !allowClearConfig.disabled; const clearIconCls = `${prefixCls}-clear-icon`; - const iconNode = - typeof allowClear === 'object' && - isReactRenderable(allowClear?.clearIcon) - ? allowClear.clearIcon - : '✖'; + const iconNode = isReactRenderable(allowClearConfig.clearIcon) + ? allowClearConfig.clearIcon + : '✖'; clearIcon = (