import {
computed,
defineComponent,
getCurrentInstance,
nextTick,
onMounted,
ref,
watch,
watchEffect,
} from 'vue';
import ClearableLabeledInput from './ClearableLabeledInput';
import ResizableTextArea from './ResizableTextArea';
import { textAreaProps } from './inputProps';
import type { InputFocusOptions } from './Input';
import { fixControlledValue, resolveOnChange, triggerFocus } from './Input';
import classNames from '../_util/classNames';
import { useInjectFormItemContext } from '../form/FormItemContext';
import type { FocusEventHandler } from '../_util/EventInterface';
import useConfigInject from '../_util/hooks/useConfigInject';
import omit from '../_util/omit';
function fixEmojiLength(value: string, maxLength: number) {
return [...(value || '')].slice(0, maxLength).join('');
}
export default defineComponent({
name: 'ATextarea',
inheritAttrs: false,
props: textAreaProps,
setup(props, { attrs, expose, emit }) {
const formItemContext = useInjectFormItemContext();
const stateValue = ref(props.value === undefined ? props.defaultValue : props.value);
const resizableTextArea = ref();
const mergedValue = ref('');
const { prefixCls, size, direction } = useConfigInject('input', props);
const showCount = computed(() => {
return (props.showCount as any) === '' || props.showCount || false;
});
// Max length value
const hasMaxLength = computed(() => Number(props.maxlength) > 0);
const compositing = ref(false);
const instance = getCurrentInstance();
watch(
() => props.value,
() => {
if ('value' in instance.vnode.props || {}) {
stateValue.value = props.value ?? '';
}
},
);
const focus = (option?: InputFocusOptions) => {
triggerFocus(resizableTextArea.value?.textArea, option);
};
const blur = () => {
resizableTextArea.value?.textArea?.blur();
};
const setValue = (value: string | number, callback?: Function) => {
if (stateValue.value === value) {
return;
}
if (props.value === undefined) {
stateValue.value = value;
} else {
nextTick(() => {
if (resizableTextArea.value.textArea.value !== mergedValue.value) {
resizableTextArea.value?.instance.update?.();
}
});
}
nextTick(() => {
callback && callback();
});
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.keyCode === 13) {
emit('pressEnter', e);
}
emit('keydown', e);
};
const onBlur: FocusEventHandler = e => {
const { onBlur } = props;
onBlur?.(e);
formItemContext.onFieldBlur();
};
const triggerChange = (e: Event) => {
emit('update:value', (e.target as HTMLInputElement).value);
emit('change', e);
emit('input', e);
formItemContext.onFieldChange();
};
const handleReset = (e: MouseEvent) => {
resolveOnChange(resizableTextArea.value.textArea, e, triggerChange);
setValue('', () => {
focus();
});
};
const handleChange = (e: Event) => {
const { value, composing } = e.target as any;
compositing.value = (e as any).isComposing || composing;
if ((compositing.value && props.lazy) || stateValue.value === value) return;
let triggerValue = (e.currentTarget as any).value;
if (hasMaxLength.value) {
triggerValue = fixEmojiLength(triggerValue, props.maxlength!);
}
resolveOnChange(e.currentTarget as any, e, triggerChange, triggerValue);
setValue(triggerValue);
};
const renderTextArea = () => {
const { style, class: customClass } = attrs;
const { bordered = true } = props;
const resizeProps = {
...omit(props, ['allowClear']),
...attrs,
style: showCount.value ? {} : style,
class: {
[`${prefixCls.value}-borderless`]: !bordered,
[`${customClass}`]: customClass && !showCount.value,
[`${prefixCls.value}-sm`]: size.value === 'small',
[`${prefixCls.value}-lg`]: size.value === 'large',
},
showCount: null,
prefixCls: prefixCls.value,
onInput: handleChange,
onChange: handleChange,
onBlur,
onKeydown: handleKeyDown,
};
if (props.valueModifiers?.lazy) {
delete resizeProps.onInput;
}
return (