Skip to content
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

Feat/textarea should support hasClear #4714

Merged
merged 4 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions components/input/__docs__/demo/clear/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ ReactDOM.render(
/>
<br />
<br />
<Input.TextArea
hasClear
defaultValue="clear by click"
aria-label="input with config of hasClear"
onChange={onChange}
/>
<br />
<br />
<Input.TextArea
hasClear
defaultValue="clear by click"
aria-label="input with config of hasClear"
onChange={onChange}
maxLength={100}
showLimitHint
/>
<br />
<br />
</div>,
mountNode
);
139 changes: 70 additions & 69 deletions components/input/__docs__/index.en-us.md

Large diffs are not rendered by default.

155 changes: 78 additions & 77 deletions components/input/__docs__/index.md

Large diffs are not rendered by default.

94 changes: 76 additions & 18 deletions components/input/__tests__/textarea-spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import React, { useState } from 'react';
import ReactTestUtils from 'react-dom/test-utils';
import ReactDOM from 'react-dom';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Expand All @@ -7,7 +8,10 @@ import assert from 'power-assert';
import Input from '../index';

Enzyme.configure({ adapter: new Adapter() });

function delay(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
/* eslint-disable no-undef, react/jsx-filename-extension */
describe('TextArea', () => {
describe('render', () => {
let parent;
Expand All @@ -23,23 +27,55 @@ describe('TextArea', () => {
});

it('should textarea isPreview', () => {
ReactDOM.render(<Input.TextArea id="ispreview-input" isPreview defaultValue="abc" />, parent);
ReactDOM.render(
<Input.TextArea id="ispreview-input" isPreview defaultValue="abc" />,
parent
);
assert(document.querySelectorAll('#ispreview-input')[0].innerText === 'abc');
});

it('should textarea isPreview compatible value null', () => {
ReactDOM.render(<Input.TextArea id="ispreview-input-null" isPreview value={null} />, parent);
ReactDOM.render(
<Input.TextArea id="ispreview-input-null" isPreview value={null} />,
parent
);
assert(document.querySelectorAll('#ispreview-input-null')[0].innerText === '');
});

it('should textarea renderPreview', () => {
ReactDOM.render(
<Input.TextArea id="renderpreview-input" isPreview defaultValue="abc" renderPreview={() => 'ddd'} />,
<Input.TextArea
id="renderpreview-input"
isPreview
defaultValue="abc"
renderPreview={() => 'ddd'}
/>,
parent
);

assert(document.querySelectorAll('#renderpreview-input')[0].innerText === 'ddd');
});
it('should support hasClear ,close #4334', async () => {
const ref = { current: null };
function Demo() {
const [value, setValue] = useState('aaa');
ref.current = { value };
return (
<Input.TextArea
value={value}
placeholder="TextArea"
aria-label="TextArea"
hasClear
onChange={v => setValue(v)}
/>
);
}
mount(<Demo />, { attachTo: parent });
await delay(100);
const btn = parent.querySelector('.next-input-clear');
ReactTestUtils.Simulate.click(btn);
assert(ref.current.value === '');
});
});

describe('behavior', () => {
Expand All @@ -48,7 +84,9 @@ describe('TextArea', () => {
const onChange = sinon.spy();
const onFocus = sinon.spy();
const onBlur = sinon.spy();
const wrapper = mount(<Input.TextArea onChange={onChange} onFocus={onFocus} onBlur={onBlur} />);
const wrapper = mount(
<Input.TextArea onChange={onChange} onFocus={onFocus} onBlur={onBlur} />
);
wrapper.find('textarea').simulate('change', { target: { value: '20' } });
assert(onChange.calledOnce);
wrapper.find('textarea').simulate('focus');
Expand Down Expand Up @@ -125,7 +163,9 @@ describe('TextArea', () => {
});

it('should support maxLength & hasLimitHint', done => {
const wrapper = mount(<Input.TextArea defaultValue={'abcd'} maxLength={10} hasLimitHint />);
const wrapper = mount(
<Input.TextArea defaultValue={'abcd'} maxLength={10} hasLimitHint />
);
assert(!wrapper.find('.next-input-len').hasClass('next-error'));

wrapper.find('textarea').simulate('change', { target: { value: '12345678901' } });
Expand Down Expand Up @@ -176,7 +216,9 @@ describe('TextArea', () => {
<Input.TextArea
ref="textarea"
onFocus={e => {
assert(this.refs.textarea.getInstance().getInputNode() !== undefined);
assert(
this.refs.textarea.getInstance().getInputNode() !== undefined
);
}}
/>
);
Expand All @@ -191,7 +233,13 @@ describe('TextArea', () => {

it('should support getValueLength', done => {
const getValueLength = sinon.spy();
mount(<Input.TextArea defaultValue="abcdef" maxLength={10} getValueLength={getValueLength} />);
mount(
<Input.TextArea
defaultValue="abcdef"
maxLength={10}
getValueLength={getValueLength}
/>
);
assert(getValueLength.calledOnce);

let getValueLength2 = value => {
Expand All @@ -208,7 +256,12 @@ describe('TextArea', () => {
assert(wrapper.find('.next-input-len').text() === '1/10');

const wrapper2 = mount(
<Input.TextArea defaultValue="abcdef" maxLength={10} hasLimitHint getValueLength={getValueLength2} />
<Input.TextArea
defaultValue="abcdef"
maxLength={10}
hasLimitHint
getValueLength={getValueLength2}
/>
);
assert(wrapper2.find('.next-input-len').text() === '1/10');

Expand All @@ -219,15 +272,23 @@ describe('TextArea', () => {
const wrapper = mount(<Input.TextArea defaultValue="abcdef" autoHeight />);
// console.log(wrapper.find('textarea[data-real]').instance().clientHeight)
// let originHeight = wrapper.find('textarea[data-real]').instance().clientHeight;
wrapper.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } });
wrapper
.find('textarea[data-real]')
.simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } });

// assert(wrapper.find('textarea[data-real]').at(0).getElement().clientHeight > originHeight);

const wrapper2 = mount(<Input.TextArea defaultValue="abcdef" autoHeight={{ minRows: 2, maxRows: 4 }} />);
const wrapper2 = mount(
<Input.TextArea defaultValue="abcdef" autoHeight={{ minRows: 2, maxRows: 4 }} />
);
// console.log(wrapper2.find('textarea[data-real]').instance().clientHeight)
// let originHeight = wrapper2.find('textarea[data-real]').instance().clientHeight;
wrapper2.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } });
wrapper2.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4' } });
wrapper2
.find('textarea[data-real]')
.simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } });
wrapper2
.find('textarea[data-real]')
.simulate('change', { target: { value: '1\n2\n3\n4' } });

//

Expand All @@ -241,10 +302,7 @@ describe('TextArea', () => {
}
}
const wrapper = mount(<App />);
wrapper
.ref('textarea')
.getInstance()
.focus();
wrapper.ref('textarea').getInstance().focus();
wrapper.update();
// assert(wrapper.find('.next-input').hasClass('next-focus'));

Expand Down
31 changes: 21 additions & 10 deletions components/input/base.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';

import ConfigProvider from '../config-provider';
import { func } from '../util';
import zhCN from '../locale/zh-cn';


class Base extends React.Component {
static propTypes = {
...ConfigProvider.propTypes,
Expand Down Expand Up @@ -240,7 +240,26 @@ class Base extends React.Component {
});
this.props.onBlur(e);
}

handleKeyDownFromClear = e => {
if (e.keyCode === 13) {
this.onClear(e);
}
};

onClear(e) {
if (this.props.disabled) {
return;
}
// 非受控模式清空内部数据
if (!('value' in this.props)) {
this.setState({
value: '',
});
}
this.props.onChange('', e, 'clear');
this.focus();
}
renderLength() {
const { maxLength, showLimitHint, prefix, rtl } = this.props;
const len = maxLength > 0 && this.state.value ? this.getValueLength(this.state.value) : 0;
Expand All @@ -252,18 +271,10 @@ class Base extends React.Component {

const content = rtl ? `${maxLength}/${len}` : `${len}/${maxLength}`;

return maxLength && showLimitHint ? <span className={classesLenWrap}>{content}</span> : null;
return maxLength && showLimitHint ? <span className={classesLenWrap}>{content}</span> : null
}

renderControl() {
const lenWrap = this.renderLength();

return lenWrap ? (
<span onClick={() => this.focus()} className={`${this.props.prefix}input-control`}>
{lenWrap}
</span>
) : null;
}

getClass() {
const { disabled, state, prefix } = this.props;
Expand Down
4 changes: 4 additions & 0 deletions components/input/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ export interface TextAreaProps extends HTMLAttributesWeak, CommonProps {
* 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange
*/
composition?: boolean;
/**
* 是否出现clear按钮
*/
hasClear?: boolean;
}

export class TextArea extends React.Component<TextAreaProps, any> {}
Expand Down
21 changes: 0 additions & 21 deletions components/input/input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -240,27 +240,6 @@ class Input extends Base {
this.onKeyDown(e);
};

handleKeyDownFromClear = e => {
if (e.keyCode === 13) {
this.onClear(e);
}
};

onClear(e) {
if (this.props.disabled) {
return;
}

// 非受控模式清空内部数据
if (!('value' in this.props)) {
this.setState({
value: '',
});
}
this.props.onChange('', e, 'clear');
this.focus();
}

render() {
const {
size,
Expand Down
Loading
Loading