UNPKG

4.86 kBJavaScriptView Raw
1import React, { forwardRef, useImperativeHandle, useRef } from 'react';
2import { useIsomorphicLayoutEffect } from 'ahooks';
3import runes from 'runes2';
4import { withNativeProps } from '../../utils/native-props';
5import { usePropsValue } from '../../utils/use-props-value';
6import { mergeProps } from '../../utils/with-default-props';
7import { devError } from '../../utils/dev-log';
8import useInputHandleKeyDown from '../../components/input/useInputHandleKeyDown';
9const classPrefix = 'adm-text-area';
10const defaultProps = {
11 rows: 2,
12 showCount: false,
13 autoSize: false,
14 defaultValue: ''
15};
16export const TextArea = forwardRef((p, ref) => {
17 const props = mergeProps(defaultProps, p);
18 const {
19 autoSize,
20 showCount,
21 maxLength
22 } = props;
23 const [value, setValue] = usePropsValue(Object.assign(Object.assign({}, props), {
24 value: props.value === null ? '' : props.value
25 }));
26 if (props.value === null) {
27 devError('TextArea', '`value` prop on `TextArea` should not be `null`. Consider using an empty string to clear the component.');
28 }
29 const nativeTextAreaRef = useRef(null);
30 // https://github.com/ant-design/ant-design-mobile/issues/5961
31 const heightRef = useRef('auto');
32 // https://github.com/ant-design/ant-design-mobile/issues/6051
33 const hiddenTextAreaRef = useRef(null);
34 const handleKeydown = useInputHandleKeyDown({
35 onEnterPress: props.onEnterPress,
36 onKeyDown: props.onKeyDown,
37 nativeInputRef: nativeTextAreaRef,
38 enterKeyHint: props.enterKeyHint
39 });
40 useImperativeHandle(ref, () => ({
41 clear: () => {
42 setValue('');
43 },
44 focus: () => {
45 var _a;
46 (_a = nativeTextAreaRef.current) === null || _a === void 0 ? void 0 : _a.focus();
47 },
48 blur: () => {
49 var _a;
50 (_a = nativeTextAreaRef.current) === null || _a === void 0 ? void 0 : _a.blur();
51 },
52 get nativeElement() {
53 return nativeTextAreaRef.current;
54 }
55 }));
56 useIsomorphicLayoutEffect(() => {
57 if (!autoSize) return;
58 const textArea = nativeTextAreaRef.current;
59 const hiddenTextArea = hiddenTextAreaRef.current;
60 if (!textArea) return;
61 textArea.style.height = heightRef.current;
62 if (!hiddenTextArea) return;
63 let height = hiddenTextArea.scrollHeight;
64 if (typeof autoSize === 'object') {
65 const computedStyle = window.getComputedStyle(textArea);
66 const lineHeight = parseFloat(computedStyle.lineHeight);
67 if (autoSize.minRows) {
68 height = Math.max(height, autoSize.minRows * lineHeight);
69 }
70 if (autoSize.maxRows) {
71 height = Math.min(height, autoSize.maxRows * lineHeight);
72 }
73 }
74 heightRef.current = `${height}px`;
75 textArea.style.height = `${height}px`;
76 }, [value, autoSize]);
77 const compositingRef = useRef(false);
78 let count;
79 const valueLength = runes(value).length;
80 if (typeof showCount === 'function') {
81 count = showCount(valueLength, maxLength);
82 } else if (showCount) {
83 count = React.createElement("div", {
84 className: `${classPrefix}-count`
85 }, maxLength === undefined ? valueLength : valueLength + '/' + maxLength);
86 }
87 let rows = props.rows;
88 if (typeof autoSize === 'object') {
89 if (autoSize.maxRows && rows > autoSize.maxRows) {
90 rows = autoSize.maxRows;
91 }
92 if (autoSize.minRows && rows < autoSize.minRows) {
93 rows = autoSize.minRows;
94 }
95 }
96 return withNativeProps(props, React.createElement("div", {
97 className: classPrefix
98 }, React.createElement("textarea", {
99 ref: nativeTextAreaRef,
100 className: `${classPrefix}-element`,
101 rows: rows,
102 value: value,
103 placeholder: props.placeholder,
104 onChange: e => {
105 let v = e.target.value;
106 if (maxLength && !compositingRef.current) {
107 v = runes(v).slice(0, maxLength).join('');
108 }
109 setValue(v);
110 },
111 id: props.id,
112 onCompositionStart: e => {
113 var _a;
114 compositingRef.current = true;
115 (_a = props.onCompositionStart) === null || _a === void 0 ? void 0 : _a.call(props, e);
116 },
117 onCompositionEnd: e => {
118 var _a;
119 compositingRef.current = false;
120 if (maxLength) {
121 const v = e.target.value;
122 setValue(runes(v).slice(0, maxLength).join(''));
123 }
124 (_a = props.onCompositionEnd) === null || _a === void 0 ? void 0 : _a.call(props, e);
125 },
126 autoComplete: props.autoComplete,
127 autoFocus: props.autoFocus,
128 disabled: props.disabled,
129 readOnly: props.readOnly,
130 name: props.name,
131 onFocus: props.onFocus,
132 onBlur: props.onBlur,
133 onClick: props.onClick,
134 onKeyDown: handleKeydown
135 }), count, autoSize && React.createElement("textarea", {
136 ref: hiddenTextAreaRef,
137 className: `${classPrefix}-element ${classPrefix}-element-hidden`,
138 value: value,
139 rows: rows,
140 "aria-hidden": true,
141 readOnly: true
142 })));
143});
144TextArea.defaultProps = defaultProps;
\No newline at end of file