import type { CSSProperties, VNode } from 'vue'; import { getCurrentInstance, watch, onBeforeUnmount, ref, nextTick, defineComponent, withDirectives, } from 'vue'; import ResizeObserver from '../vc-resize-observer'; import classNames from '../_util/classNames'; import calculateNodeHeight from './calculateNodeHeight'; import raf from '../_util/raf'; import warning from '../_util/warning'; import BaseMixin from '../_util/BaseMixin'; import antInput from '../_util/antInputDirective'; import omit from '../_util/omit'; import { textAreaProps } from './inputProps'; const RESIZE_STATUS_NONE = 0; const RESIZE_STATUS_RESIZING = 1; const RESIZE_STATUS_RESIZED = 2; const ResizableTextArea = defineComponent({ name: 'ResizableTextArea', mixins: [BaseMixin], inheritAttrs: false, props: textAreaProps, setup(props, { attrs, emit, expose }) { let nextFrameActionId: any; let resizeFrameId: any; const textAreaRef = ref(); const textareaStyles = ref({}); const resizeStatus = ref(RESIZE_STATUS_NONE); onBeforeUnmount(() => { raf.cancel(nextFrameActionId); raf.cancel(resizeFrameId); }); // https://github.com/ant-design/ant-design/issues/21870 const fixFirefoxAutoScroll = () => { try { if (document.activeElement === textAreaRef.value) { const currentStart = textAreaRef.value.selectionStart; const currentEnd = textAreaRef.value.selectionEnd; textAreaRef.value.setSelectionRange(currentStart, currentEnd); } } catch (e) { // Fix error in Chrome: // Failed to read the 'selectionStart' property from 'HTMLInputElement' // http://stackoverflow.com/q/21177489/3040605 } }; const resizeTextarea = () => { const autoSize = props.autoSize || props.autosize; if (!autoSize || !textAreaRef.value) { return; } const { minRows, maxRows } = autoSize; textareaStyles.value = calculateNodeHeight(textAreaRef.value, false, minRows, maxRows); resizeStatus.value = RESIZE_STATUS_RESIZING; raf.cancel(resizeFrameId); resizeFrameId = raf(() => { resizeStatus.value = RESIZE_STATUS_RESIZED; resizeFrameId = raf(() => { resizeStatus.value = RESIZE_STATUS_NONE; fixFirefoxAutoScroll(); }); }); }; const resizeOnNextFrame = () => { raf.cancel(nextFrameActionId); nextFrameActionId = raf(resizeTextarea); }; const handleResize = (size: { width: number; height: number }) => { if (resizeStatus.value !== RESIZE_STATUS_NONE) { return; } emit('resize', size); const autoSize = props.autoSize || props.autosize; if (autoSize) { resizeOnNextFrame(); } }; warning( props.autosize === undefined, 'Input.TextArea', 'autosize is deprecated, please use autoSize instead.', ); const renderTextArea = () => { const { prefixCls, autoSize, autosize, disabled } = props; const otherProps = omit(props, [ 'prefixCls', 'onPressEnter', 'autoSize', 'autosize', 'defaultValue', 'allowClear', 'type', 'lazy', 'maxlength', ]); const cls = classNames(prefixCls, attrs.class, { [`${prefixCls}-disabled`]: disabled, }); const style = { ...(attrs.style as CSSProperties), ...textareaStyles.value, ...(resizeStatus.value === RESIZE_STATUS_RESIZING ? { overflowX: 'hidden', overflowY: 'hidden' } : null), }; const textareaProps: any = { ...otherProps, ...attrs, style, class: cls, }; if (!textareaProps.autofocus) { delete textareaProps.autofocus; } return ( {withDirectives((