Skip to content

Commit 356e60a

Browse files
committed
feat: update textarea
1 parent f39da91 commit 356e60a

25 files changed

+745
-403
lines changed

build/config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
22
dev: {
3-
componentName: 'slider', // dev components
3+
componentName: 'input', // dev components
44
},
55
};

components/affix/index.jsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import PropTypes from '../_util/vue-types';
2-
import addEventListener from '../vc-util/Dom/addEventListener';
32
import classNames from 'classnames';
43
import shallowequal from 'shallowequal';
54
import omit from 'omit.js';
6-
import getScroll from '../_util/getScroll';
5+
import ResizeObserver from '../vc-resize-observer';
76
import BaseMixin from '../_util/BaseMixin';
87
import throttleByAnimationFrame from '../_util/throttleByAnimationFrame';
98
import { ConfigConsumerProps } from '../config-provider';
@@ -242,11 +241,17 @@ const Affix = {
242241
attrs: omit($props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target']),
243242
};
244243
return (
245-
<div {...props} style={placeholderStyle} ref="placeholderNode">
246-
<div class={className} ref="fixedNode" style={affixStyle}>
247-
{$slots.default}
244+
<ResizeObserver
245+
onResize={() => {
246+
this.updatePosition();
247+
}}
248+
>
249+
<div {...props} style={placeholderStyle} ref="placeholderNode">
250+
<div class={className} ref="fixedNode" style={affixStyle}>
251+
{$slots.default}
252+
</div>
248253
</div>
249-
</div>
254+
</ResizeObserver>
250255
);
251256
},
252257
};
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import classNames from 'classnames';
2+
import Icon from '../icon';
3+
import { getInputClassName } from './Input';
4+
import PropTypes from '../_util/vue-types';
5+
import { cloneElement } from '../_util/vnode';
6+
import { getComponentFromProp } from '../_util/props-util';
7+
8+
export function hasPrefixSuffix(instance) {
9+
return !!(
10+
getComponentFromProp(instance, 'prefix') ||
11+
getComponentFromProp(instance, 'suffix') ||
12+
instance.$props.allowClear
13+
);
14+
}
15+
16+
const ClearableInputType = ['text', 'input'];
17+
18+
const ClearableLabeledInput = {
19+
props: {
20+
prefixCls: PropTypes.string,
21+
inputType: PropTypes.oneOf(ClearableInputType),
22+
value: PropTypes.any,
23+
defaultValue: PropTypes.any,
24+
allowClear: PropTypes.bool,
25+
element: PropTypes.any,
26+
handleReset: PropTypes.func,
27+
disabled: PropTypes.bool,
28+
size: PropTypes.oneOf(['small', 'large', 'default']),
29+
suffix: PropTypes.any,
30+
prefix: PropTypes.any,
31+
addonBefore: PropTypes.any,
32+
addonAfter: PropTypes.any,
33+
className: PropTypes.string,
34+
},
35+
methods: {
36+
renderClearIcon(prefixCls) {
37+
const { allowClear, value, disabled, inputType, handleReset } = this.$props;
38+
if (!allowClear || disabled || value === undefined || value === null || value === '') {
39+
return null;
40+
}
41+
const className =
42+
inputType === ClearableInputType[0]
43+
? `${prefixCls}-textarea-clear-icon`
44+
: `${prefixCls}-clear-icon`;
45+
return (
46+
<Icon
47+
type="close-circle"
48+
theme="filled"
49+
onClick={handleReset}
50+
class={className}
51+
role="button"
52+
/>
53+
);
54+
},
55+
56+
renderSuffix(prefixCls) {
57+
const { suffix, allowClear } = this.$props;
58+
if (suffix || allowClear) {
59+
return (
60+
<span class={`${prefixCls}-suffix`}>
61+
{this.renderClearIcon(prefixCls)}
62+
{suffix}
63+
</span>
64+
);
65+
}
66+
return null;
67+
},
68+
69+
renderLabeledIcon(prefixCls, element) {
70+
const props = this.$props;
71+
const suffix = this.renderSuffix(prefixCls);
72+
if (!hasPrefixSuffix(this)) {
73+
return cloneElement(element, {
74+
props: { value: props.value },
75+
});
76+
}
77+
78+
const prefix = props.prefix ? (
79+
<span class={`${prefixCls}-prefix`}>{props.prefix}</span>
80+
) : null;
81+
82+
const affixWrapperCls = classNames(props.className, `${prefixCls}-affix-wrapper`, {
83+
[`${prefixCls}-affix-wrapper-sm`]: props.size === 'small',
84+
[`${prefixCls}-affix-wrapper-lg`]: props.size === 'large',
85+
[`${prefixCls}-affix-wrapper-input-with-clear-btn`]:
86+
props.suffix && props.allowClear && this.$props.value,
87+
});
88+
return (
89+
<span class={affixWrapperCls} style={props.style}>
90+
{prefix}
91+
{cloneElement(element, {
92+
style: null,
93+
props: { value: props.value },
94+
class: getInputClassName(prefixCls, props.size, props.disabled),
95+
})}
96+
{suffix}
97+
</span>
98+
);
99+
},
100+
101+
renderInputWithLabel(prefixCls, labeledElement) {
102+
const { addonBefore, addonAfter, style, size, className } = this.$props;
103+
// Not wrap when there is not addons
104+
if (!addonBefore && !addonAfter) {
105+
return labeledElement;
106+
}
107+
108+
const wrapperClassName = `${prefixCls}-group`;
109+
const addonClassName = `${wrapperClassName}-addon`;
110+
const addonBeforeNode = addonBefore ? (
111+
<span class={addonClassName}>{addonBefore}</span>
112+
) : null;
113+
const addonAfterNode = addonAfter ? <span class={addonClassName}>{addonAfter}</span> : null;
114+
115+
const mergedWrapperClassName = classNames(`${prefixCls}-wrapper`, {
116+
[wrapperClassName]: addonBefore || addonAfter,
117+
});
118+
119+
const mergedGroupClassName = classNames(className, `${prefixCls}-group-wrapper`, {
120+
[`${prefixCls}-group-wrapper-sm`]: size === 'small',
121+
[`${prefixCls}-group-wrapper-lg`]: size === 'large',
122+
});
123+
124+
// Need another wrapper for changing display:table to display:inline-block
125+
// and put style prop in wrapper
126+
return (
127+
<span class={mergedGroupClassName} style={style}>
128+
<span class={mergedWrapperClassName}>
129+
{addonBeforeNode}
130+
{cloneElement(labeledElement, { style: null })}
131+
{addonAfterNode}
132+
</span>
133+
</span>
134+
);
135+
},
136+
137+
renderTextAreaWithClearIcon(prefixCls, element) {
138+
const { value, allowClear, className, style } = this.$props;
139+
if (!allowClear) {
140+
return cloneElement(element, {
141+
props: { value },
142+
});
143+
}
144+
const affixWrapperCls = classNames(
145+
className,
146+
`${prefixCls}-affix-wrapper`,
147+
`${prefixCls}-affix-wrapper-textarea-with-clear-btn`,
148+
);
149+
return (
150+
<span class={affixWrapperCls} style={style}>
151+
{cloneElement(element, {
152+
style: null,
153+
props: { value },
154+
})}
155+
{this.renderClearIcon(prefixCls)}
156+
</span>
157+
);
158+
},
159+
160+
renderClearableLabeledInput() {
161+
const { prefixCls, inputType, element } = this.$props;
162+
if (inputType === ClearableInputType[0]) {
163+
return this.renderTextAreaWithClearIcon(prefixCls, element);
164+
}
165+
return this.renderInputWithLabel(prefixCls, this.renderLabeledIcon(prefixCls, element));
166+
},
167+
},
168+
render() {
169+
return this.renderClearableLabeledInput();
170+
},
171+
};
172+
173+
export default ClearableLabeledInput;

0 commit comments

Comments
 (0)