You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ant-design-vue/components/input/TextArea.jsx

187 lines
4.5 KiB

6 years ago
import classNames from 'classnames';
import omit from 'omit.js';
import ResizeObserver from 'resize-observer-polyfill';
import inputProps from './inputProps';
import calculateNodeHeight from './calculateNodeHeight';
import hasProp from '../_util/props-util';
6 years ago
import { ConfigConsumerProps } from '../config-provider';
function onNextFrame(cb) {
7 years ago
if (window.requestAnimationFrame) {
return window.requestAnimationFrame(cb);
7 years ago
}
return window.setTimeout(cb, 1);
7 years ago
}
function clearNextFrameAction(nextFrameId) {
7 years ago
if (window.cancelAnimationFrame) {
window.cancelAnimationFrame(nextFrameId);
7 years ago
} else {
window.clearTimeout(nextFrameId);
7 years ago
}
}
function fixControlledValue(value) {
7 years ago
if (typeof value === 'undefined' || value === null) {
return '';
7 years ago
}
return value;
7 years ago
}
function noop() {}
7 years ago
export default {
name: 'ATextarea',
7 years ago
model: {
prop: 'value',
event: 'change.value',
},
props: {
...inputProps,
autosize: [Object, Boolean],
},
6 years ago
inject: {
configProvider: { default: () => ConfigConsumerProps },
6 years ago
},
data() {
const { value, defaultValue } = this.$props;
7 years ago
return {
7 years ago
stateValue: fixControlledValue(!hasProp(this, 'value') ? defaultValue : value),
7 years ago
nextFrameActionId: undefined,
textareaStyles: {},
};
7 years ago
},
computed: {},
7 years ago
watch: {
value(val) {
this.$nextTick(() => {
this.resizeOnNextFrame();
});
this.stateValue = fixControlledValue(val);
},
autosize(val) {
if (!val && this.$refs.textArea) {
this.textareaStyles = omit(this.textareaStyles, ['overflowY']);
7 years ago
}
},
},
mounted() {
this.$nextTick(() => {
this.resizeTextarea();
this.updateResizeObserverHook();
if (this.autoFocus) {
this.focus();
}
});
7 years ago
},
updated() {
this.updateResizeObserverHook();
},
beforeDestroy() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
}
},
7 years ago
methods: {
resizeOnNextFrame() {
if (this.nextFrameActionId) {
clearNextFrameAction(this.nextFrameActionId);
}
this.nextFrameActionId = onNextFrame(this.resizeTextarea);
},
// We will update hooks if `autosize` prop change
updateResizeObserverHook() {
if (!this.resizeObserver && this.$props.autosize) {
// Add resize observer
this.resizeObserver = new ResizeObserver(this.resizeOnNextFrame);
this.resizeObserver.observe(this.$refs.textArea);
} else if (this.resizeObserver && !this.$props.autosize) {
// Remove resize observer
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
},
handleKeyDown(e) {
7 years ago
if (e.keyCode === 13) {
this.$emit('pressEnter', e);
7 years ago
}
this.$emit('keydown', e);
7 years ago
},
resizeTextarea() {
const { autosize } = this.$props;
7 years ago
if (!autosize || !this.$refs.textArea) {
return;
7 years ago
}
6 years ago
const { minRows, maxRows } = autosize;
const textareaStyles = calculateNodeHeight(this.$refs.textArea, false, minRows, maxRows);
this.textareaStyles = textareaStyles;
7 years ago
},
handleTextareaChange(e) {
if (e.target.composing) return;
7 years ago
if (!hasProp(this, 'value')) {
this.stateValue = e.target.value;
this.resizeTextarea();
7 years ago
} else {
this.$forceUpdate();
}
if (!e.target.composing) {
this.$emit('change.value', e.target.value);
7 years ago
}
this.$emit('change', e);
this.$emit('input', e);
7 years ago
},
focus() {
this.$refs.textArea.focus();
7 years ago
},
blur() {
this.$refs.textArea.blur();
7 years ago
},
},
render() {
const {
stateValue,
7 years ago
handleKeyDown,
handleTextareaChange,
textareaStyles,
$attrs,
$listeners,
6 years ago
prefixCls: customizePrefixCls,
disabled,
} = this;
7 years ago
const otherProps = omit(this.$props, [
'prefixCls',
'autosize',
'type',
'value',
'defaultValue',
]);
const getPrefixCls = this.configProvider.getPrefixCls;
6 years ago
const prefixCls = getPrefixCls('input', customizePrefixCls);
const cls = classNames(prefixCls, {
[`${prefixCls}-disabled`]: disabled,
});
7 years ago
const textareaProps = {
directives: [{ name: 'ant-input' }],
7 years ago
attrs: { ...otherProps, ...$attrs },
on: {
...$listeners,
keydown: handleKeyDown,
input: handleTextareaChange,
change: noop,
7 years ago
},
};
7 years ago
return (
<textarea
7 years ago
{...textareaProps}
7 years ago
value={stateValue}
6 years ago
class={cls}
7 years ago
style={textareaStyles}
ref="textArea"
7 years ago
/>
);
7 years ago
},
};