feat: textarea support word count (#3009)

pull/3048/head
John60676 2020-10-26 11:28:56 +08:00 committed by GitHub
parent 9ac18c5e52
commit 2fb52d6e26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 7 deletions

View File

@ -34,7 +34,6 @@ const ClearableLabeledInput = {
addonAfter: PropTypes.any,
readonly: PropTypes.bool,
isFocused: PropTypes.bool,
style: PropTypes.object,
},
methods: {
renderClearIcon(prefixCls) {
@ -74,6 +73,7 @@ const ClearableLabeledInput = {
renderLabeledIcon(prefixCls, element) {
const props = this.$props;
const { style } = this.$attrs;
const suffix = this.renderSuffix(prefixCls);
if (!hasPrefixSuffix(this)) {
return cloneElement(element, {
@ -94,7 +94,7 @@ const ClearableLabeledInput = {
props.suffix && props.allowClear && this.$props.value,
});
return (
<span class={affixWrapperCls} style={props.style}>
<span class={affixWrapperCls} style={style}>
{prefix}
{cloneElement(element, {
style: null,

View File

@ -6,11 +6,13 @@ import { hasProp, getOptionProps } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import { fixControlledValue, resolveOnChange } from './Input';
import PropTypes from '../_util/vue-types';
import classNames from '../_util/classNames';
const TextAreaProps = {
...inputProps,
autosize: PropTypes.oneOfType([Object, Boolean]),
autoSize: PropTypes.oneOfType([Object, Boolean]),
showCount: PropTypes.bool,
};
export default {
@ -100,9 +102,13 @@ export default {
renderTextArea(prefixCls) {
const props = getOptionProps(this);
const { style, class: customClass } = this.$attrs;
const resizeProps = {
...props,
...this.$attrs,
style: style && !props.showCount,
class: customClass && !props.showCount,
showCount: null,
prefixCls,
onInput: this.handleChange,
onChange: this.handleChange,
@ -112,19 +118,44 @@ export default {
},
},
render() {
const { stateValue, prefixCls: customizePrefixCls } = this;
const { stateValue, prefixCls: customizePrefixCls, maxlength, showCount } = this;
const { style, class: customClass } = this.$attrs;
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('input', customizePrefixCls);
let value = fixControlledValue(stateValue);
// Max length value
const hasMaxlength = Number(maxlength) > 0;
value = hasMaxlength ? value.slice(0, maxlength) : value;
const props = {
...getOptionProps(this),
...this.$attrs,
prefixCls,
inputType: 'text',
value: fixControlledValue(stateValue),
element: this.renderTextArea(prefixCls),
handleReset: this.handleReset,
};
return <ClearableLabeledInput {...props} ref={this.saveClearableInput} />;
let textareaNode = (
<ClearableLabeledInput {...props} value={value} ref={this.saveClearableInput} />
);
if (showCount) {
const valueLength = [...value].length;
const dataCount = `${valueLength}${hasMaxlength ? ` / ${maxlength}` : ''}`;
textareaNode = (
<div
className={classNames(
`${prefixCls}-textarea`,
`${prefixCls}-textarea-show-count`,
customClass,
)}
style={style}
data-count={dataCount}
>
{textareaNode}
</div>
);
}
return textareaNode;
},
};

View File

@ -7,3 +7,5 @@ exports[`Input.Search should support suffix 1`] = `<span class="ant-input-search
exports[`TextArea should support disabled 1`] = `<textarea disabled="" class="ant-input ant-input-disabled"></textarea>`;
exports[`TextArea should support maxlength 1`] = `<textarea maxlength="10" class="ant-input"></textarea>`;
exports[`TextArea should support showCount 1`] = `<div class="ant-input-textarea ant-input-textarea-show-count" data-count="3 / 10"><textarea maxlength="10" class="ant-input"></textarea></div>`;

View File

@ -29,7 +29,7 @@ describe('Input', () => {
props: { allowClear: true, defaultValue: '111', disabled: true },
sync: false,
});
expect(wrapper.findAll('.ant-input-clear-icon').length).toBe(0);
expect(wrapper.findAll('.ant-input-clear-icon-hidden').length).toBeTruthy();
});
});
@ -68,6 +68,17 @@ describe('TextArea', () => {
expect(wrapper.html()).toMatchSnapshot();
});
});
it('should support showCount', async () => {
const wrapper = mount(TextArea, {
props: { showCount: true, defaultValue: '111', maxlength: 10 },
sync: false,
});
expect(wrapper.find('.ant-input-textarea-show-count')).toBeTruthy();
await asyncExpect(() => {
expect(wrapper.html()).toMatchSnapshot();
});
});
});
// describe('As Form Control', () => {

View File

@ -57,4 +57,13 @@
margin: 8px 8px 0 0;
}
.@{ant-prefix}-input-textarea {
&-show-count::after {
display: block;
color: @text-color-secondary;
text-align: right;
content: attr(data-count);
}
}
@import './search-input';

View File

@ -31,5 +31,6 @@ export declare class TextArea extends AntdComponent {
* @type boolean
*/
allowClear?: boolean;
showCount?: boolean;
};
}