Browse Source

feat: input semantic dom (#41493)

* feat: input semantic dom

* chore: update deps

* docs: add toc
pull/41469/head
MadCcc 2 years ago
committed by GitHub
parent
commit
72a03efead
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      components/input/Input.tsx
  2. 5
      components/input/TextArea.tsx
  3. 102
      components/input/__tests__/__snapshots__/index.test.tsx.snap
  4. 29
      components/input/__tests__/__snapshots__/textarea.test.tsx.snap
  5. 76
      components/input/__tests__/index.test.tsx
  6. 41
      components/input/__tests__/textarea.test.tsx
  7. 4
      components/input/index.en-US.md
  8. 22
      components/input/index.zh-CN.md
  9. 4
      package.json

9
components/input/Input.tsx

@ -58,7 +58,7 @@ export function triggerFocus(
export interface InputProps
extends Omit<
RcInputProps,
'wrapperClassName' | 'groupClassName' | 'inputClassName' | 'affixWrapperClassName'
'wrapperClassName' | 'groupClassName' | 'inputClassName' | 'affixWrapperClassName' | 'classes'
> {
rootClassName?: string;
size?: SizeType;
@ -84,6 +84,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
className,
rootClassName,
onChange,
classNames: classes,
...rest
} = props;
const { getPrefixCls, direction, input } = React.useContext(ConfigContext);
@ -187,7 +188,8 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
</NoCompactStyle>
)
}
classes={{
classNames={{
...classes,
input: classNames(
{
[`${prefixCls}-sm`]: mergedSize === 'small',
@ -196,8 +198,11 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
[`${prefixCls}-borderless`]: !bordered,
},
!inputHasPrefixSuffix && getStatusClassNames(prefixCls, mergedStatus),
classes?.input,
hashId,
),
}}
classes={{
affixWrapper: classNames(
{
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',

5
components/input/TextArea.tsx

@ -39,6 +39,7 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
status: customStatus,
allowClear,
showCount,
classNames: classes,
...rest
},
ref,
@ -103,6 +104,9 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus),
hashId,
),
}}
classNames={{
...classes,
textarea: classNames(
{
[`${prefixCls}-borderless`]: !bordered,
@ -111,6 +115,7 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
},
getStatusClassNames(prefixCls, mergedStatus),
hashId,
classes?.textarea,
),
}}
prefixCls={prefixCls}

102
components/input/__tests__/__snapshots__/index.test.tsx.snap

@ -328,6 +328,108 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
</span>
`;
exports[`Input allowClear should support classNames and styles 1`] = `
<div>
<span
class="rc-input-affix-wrapper custom-class"
style="background-color: red;"
>
<span
class="rc-input-prefix custom-prefix"
style="color: blue;"
>
prefix
</span>
<input
class="rc-input custom-input"
style="color: red;"
type="text"
value="123"
/>
<span
class="rc-input-suffix custom-suffix"
style="color: yellow;"
>
<span
class="rc-input-show-count-suffix rc-input-show-count-has-suffix custom-count"
style="color: green;"
>
3
</span>
suffix
</span>
</span>
<span
class="rc-input-group-wrapper custom-class"
style="background-color: red;"
>
<span
class="rc-input-wrapper rc-input-group"
>
<span
class="rc-input-affix-wrapper"
>
<span
class="rc-input-prefix custom-prefix"
style="color: blue;"
>
prefix
</span>
<input
class="rc-input custom-input"
style="color: red;"
type="text"
value="123"
/>
<span
class="rc-input-suffix custom-suffix"
style="color: yellow;"
>
<span
class="rc-input-show-count-suffix rc-input-show-count-has-suffix custom-count"
style="color: green;"
>
3
</span>
suffix
</span>
</span>
<span
class="rc-input-group-addon"
>
addon
</span>
</span>
</span>
<input
class="rc-input custom-input custom-class"
style="color: red; background-color: red;"
type="text"
value="123"
/>
<span
class="rc-input-group-wrapper custom-class"
style="background-color: red;"
>
<span
class="rc-input-wrapper rc-input-group"
>
<input
class="rc-input custom-input"
style="color: red;"
type="text"
value="123"
/>
<span
class="rc-input-group-addon"
>
addon
</span>
</span>
</span>
</div>
`;
exports[`Input rtl render component should be rendered correctly in RTL direction 1`] = `
<input
class="ant-input ant-input-rtl"

29
components/input/__tests__/__snapshots__/textarea.test.tsx.snap

@ -1,5 +1,34 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TextArea allowClear classNames and styles should work 1`] = `
<div>
<textarea
class="ant-input custom-textarea custom-class"
style="color: red; background: red;"
/>
<span
class="ant-input-affix-wrapper custom-class ant-input-textarea-affix-wrapper ant-input-textarea-show-count ant-input-show-count"
data-count="0"
style="background: red;"
>
<textarea
class="ant-input custom-textarea"
style="color: red;"
/>
<span
class="ant-input-suffix"
>
<span
class="ant-input-data-count custom-count"
style="color: blue;"
>
0
</span>
</span>
</span>
</div>
`;
exports[`TextArea allowClear should change type when click 1`] = `
<span
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper ant-input-textarea-allow-clear"

76
components/input/__tests__/index.test.tsx

@ -441,6 +441,82 @@ describe('Input allowClear', () => {
const { container } = render(<Input allowClear={{ clearIcon: 'clear' }} />);
expect(container.querySelector('.ant-input-clear-icon')?.textContent).toBe('clear');
});
it('should support classNames and styles', () => {
const { container } = render(
<>
<Input
value="123"
showCount
prefixCls="rc-input"
prefix="prefix"
suffix="suffix"
className="custom-class"
style={{ backgroundColor: 'red' }}
classNames={{
input: 'custom-input',
prefix: 'custom-prefix',
suffix: 'custom-suffix',
count: 'custom-count',
}}
styles={{
input: { color: 'red' },
prefix: { color: 'blue' },
suffix: { color: 'yellow' },
count: { color: 'green' },
}}
/>
<Input
value="123"
addonAfter="addon"
showCount
prefixCls="rc-input"
prefix="prefix"
suffix="suffix"
className="custom-class"
style={{ backgroundColor: 'red' }}
classNames={{
input: 'custom-input',
prefix: 'custom-prefix',
suffix: 'custom-suffix',
count: 'custom-count',
}}
styles={{
input: { color: 'red' },
prefix: { color: 'blue' },
suffix: { color: 'yellow' },
count: { color: 'green' },
}}
/>
<Input
value="123"
prefixCls="rc-input"
className="custom-class"
style={{ backgroundColor: 'red' }}
classNames={{
input: 'custom-input',
}}
styles={{
input: { color: 'red' },
}}
/>
<Input
value="123"
prefixCls="rc-input"
className="custom-class"
addonAfter="addon"
style={{ backgroundColor: 'red' }}
classNames={{
input: 'custom-input',
}}
styles={{
input: { color: 'red' },
}}
/>
</>,
);
expect(container).toMatchSnapshot();
});
});
describe('typescript types', () => {

41
components/input/__tests__/textarea.test.tsx

@ -579,4 +579,45 @@ describe('TextArea allowClear', () => {
const { container } = render(<TextArea allowClear={{ clearIcon: 'clear' }} />);
expect(container.querySelector('.ant-input-clear-icon')?.textContent).toBe('clear');
});
it('classNames and styles should work', () => {
const { container } = render(
<>
<TextArea
className="custom-class"
style={{ background: 'red' }}
classNames={{
textarea: 'custom-textarea',
count: 'custom-count',
}}
styles={{
textarea: {
color: 'red',
},
count: {
color: 'blue',
},
}}
/>
<TextArea
showCount
className="custom-class"
style={{ background: 'red' }}
classNames={{
textarea: 'custom-textarea',
count: 'custom-count',
}}
styles={{
textarea: {
color: 'red',
},
count: {
color: 'blue',
},
}}
/>
</>,
);
expect(container).toMatchSnapshot();
});
});

4
components/input/index.en-US.md

@ -51,12 +51,14 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca
| addonBefore | The label text displayed before (on the left side of) the input field | ReactNode | - | |
| allowClear | If allow to remove input content with clear icon | boolean \| { clearIcon: ReactNode } | false | |
| bordered | Whether has border style | boolean | true | 4.5.0 |
| classNames | Semantic DOM class | Record<[SemanticDOM](#input-1), string> | - | 5.4.0 |
| defaultValue | The initial input content | string | - | |
| disabled | Whether the input is disabled | boolean | false | |
| id | The ID for input | string | - | |
| maxLength | The max length | number | - | |
| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => ReactNode } | false | 4.18.0 info.value: 4.23.0 |
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
| styles | Semantic DOM style | Record<[SemanticDOM](#input-1), CSSProperties> | - | 5.4.0 |
| prefix | The prefix icon for the Input | ReactNode | - | |
| size | The size of the input box. Note: in the context of a form, the `middle` size is used | `large` \| `middle` \| `small` | - | |
| suffix | The suffix icon for the Input | ReactNode | - | |
@ -76,9 +78,11 @@ The rest of the props of Input are exactly the same as the original [input](http
| allowClear | If allow to remove input content with clear icon | boolean | false | |
| autoSize | Height autosize feature, can be set to true \| false or an object { minRows: 2, maxRows: 6 } | boolean \| object | false | |
| bordered | Whether has border style | boolean | true | 4.5.0 |
| classNames | Semantic DOM class | Record<[SemanticDOM](#inputtextarea-1), string> | - | 5.4.0 |
| defaultValue | The initial input content | string | - | |
| maxLength | The max length | number | - | 4.7.0 |
| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | 4.7.0 formatter: 4.10.0 info.value: 4.23.0 |
| styles | Semantic DOM style | Record<[SemanticDOM](#inputtextarea-1), CSSProperties> | - | 5.4.0 |
| value | The input content value | string | - | |
| onPressEnter | The callback function that is triggered when Enter key is pressed | function(e) | - | |
| onResize | The callback function that is triggered when resize | function({ width, height }) | - | |

22
components/input/index.zh-CN.md

@ -52,12 +52,14 @@ demo:
| addonBefore | 带标签的 input,设置前置标签 | ReactNode | - | |
| allowClear | 可以点击清除图标删除内容 | boolean \| { clearIcon: ReactNode } | - | |
| bordered | 是否有边框 | boolean | true | 4.5.0 |
| classNames | 语义化结构 class | Record<[SemanticDOM](#input-1), string> | - | 5.4.0 |
| defaultValue | 输入框默认内容 | string | - | |
| disabled | 是否禁用状态,默认为 false | boolean | false | |
| id | 输入框的 id | string | - | |
| maxLength | 最大长度 | number | - | |
| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => ReactNode } | false | 4.18.0 info.value: 4.23.0 |
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
| styles | 语义化结构 style | Record<[SemanticDOM](#input-1), CSSProperties> | - | 5.4.0 |
| prefix | 带有前缀图标的 input | ReactNode | - | |
| size | 控件大小。注:标准表单内的输入框大小限制为 `middle` | `large` \| `middle` \| `small` | - | |
| suffix | 带有后缀图标的 input | ReactNode | - | |
@ -77,9 +79,11 @@ Input 的其他属性和 React 自带的 [input](https://reactjs.org/docs/dom-el
| allowClear | 可以点击清除图标删除内容 | boolean | false | |
| autoSize | 自适应内容高度,可设置为 true \| false 或对象:{ minRows: 2, maxRows: 6 } | boolean \| object | false | |
| bordered | 是否有边框 | boolean | true | 4.5.0 |
| classNames | 语义化结构 class | Record<[SemanticDOM](#inputtextarea-1), string> | - | 5.4.0 |
| defaultValue | 输入框默认内容 | string | - | |
| maxLength | 内容最大长度 | number | - | 4.7.0 |
| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | 4.7.0 formatter: 4.10.0 info.value: 4.23.0 |
| styles | 语义化结构 style | Record<[SemanticDOM](#inputtextarea-1), CSSProperties> | - | 5.4.0 |
| value | 输入框内容 | string | - | |
| onPressEnter | 按下回车的回调 | function(e) | - | |
| onResize | resize 回调 | function({ width, height }) | - | |
@ -117,6 +121,24 @@ Input 的其他属性和 React 自带的 [input](https://reactjs.org/docs/dom-el
| blur | 取消焦点 | - | |
| focus | 获取焦点 | (option?: { preventScroll?: boolean, cursor?: 'start' \| 'end' \| 'all' }) | option - 4.10.0 |
### Semantic DOM
#### Input
| 名称 | 说明 | 版本 |
| ------ | ------------------ | ----- |
| input | `input` 元素 | 5.4.0 |
| prefix | 所有前缀的包裹元素 | 5.4.0 |
| suffix | 所有后缀的包裹元素 | 5.4.0 |
| count | 文字计数元素 | 5.4.0 |
#### Input.TextArea
| 名称 | 说明 | 版本 |
| -------- | --------------- | ----- |
| textarea | `textarea` 元素 | 5.4.0 |
| count | 文字计数元素 | 5.4.0 |
## FAQ
### 为什么我动态改变 `prefix/suffix/showCount` 时,Input 会失去焦点?

4
package.json

@ -128,7 +128,7 @@
"rc-dropdown": "~4.0.0",
"rc-field-form": "~1.29.0",
"rc-image": "~5.16.0",
"rc-input": "~1.0.3",
"rc-input": "~1.0.4",
"rc-input-number": "~7.4.0",
"rc-mentions": "~2.2.0",
"rc-menu": "~9.8.2",
@ -146,7 +146,7 @@
"rc-switch": "~4.0.0",
"rc-table": "~7.31.0",
"rc-tabs": "~12.5.6",
"rc-textarea": "~1.2.1",
"rc-textarea": "~1.2.2",
"rc-tooltip": "~6.0.0",
"rc-tree": "~5.7.0",
"rc-tree-select": "~5.8.0",

Loading…
Cancel
Save