-
Notifications
You must be signed in to change notification settings - Fork 121
/
textArea.tsx
96 lines (82 loc) · 2.73 KB
/
textArea.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import React from 'react';
import RcTextArea, { TextAreaProps } from 'rc-textarea';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import { useEffect, useRef } from 'react';
import { omit } from 'lodash';
import { classNames, getBEMElement, getBEMModifier } from 'mo/common/className';
import { fixControlledValue, inputClassName, resolveOnChange } from './input';
export interface ITextAreaProps extends TextAreaProps {
showCount?: boolean;
maxLength?: number;
onChange?: (
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
) => void;
}
const textAreaClassName = getBEMElement(inputClassName, 'textarea');
const showCountClassName = getBEMModifier(textAreaClassName, 'show-count');
export const TextArea = ({
showCount = false,
maxLength,
className,
style,
onChange,
...props
}: ITextAreaProps) => {
const innerRef = useRef(null);
const [value, setValue] = useMergedState(props.defaultValue, {
value: props.value,
});
const prevValue = useRef(props.value);
useEffect(() => {
if (props.value !== undefined || prevValue.current !== props.value) {
setValue(props.value);
prevValue.current = props.value;
}
}, [props.value, prevValue.current]);
const handleSetValue = (val: string) => {
if (props.value === undefined) {
setValue(val);
}
};
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
handleSetValue(e.target.value);
resolveOnChange(innerRef.current!, e, onChange);
};
const otherProps = omit(props, ['value']);
const textArea = (
<RcTextArea
{...otherProps}
value={value}
maxLength={maxLength}
className={classNames(className && !showCount ? [className!] : '')}
style={showCount ? {} : style}
prefixCls={inputClassName}
onChange={handleChange}
ref={innerRef}
/>
);
let val = fixControlledValue(value) as string;
const hasMaxLength = Number(maxLength) > 0;
val = hasMaxLength ? [...val].slice(0, maxLength).join('') : val;
// Only show text area wrapper when needed
if (showCount) {
const valueLength = [...val].length;
const dataCount = `${valueLength}${
hasMaxLength ? ` / ${maxLength}` : ''
}`;
return (
<div
className={classNames(
className,
textAreaClassName,
showCountClassName
)}
style={style}
data-count={dataCount}
>
{textArea}
</div>
);
}
return textArea;
};