-
Notifications
You must be signed in to change notification settings - Fork 126
/
TextareaCounter.tsx
73 lines (65 loc) · 2.69 KB
/
TextareaCounter.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
import React, { SyntheticEvent, useContext, useCallback, useImperativeHandle, useState } from 'react';
import propTypes from 'prop-types';
import { safePropTypesInstanceOf } from '../../lib/SSRSafe';
import { forwardRefAndName } from '../../lib/forwardRefAndName';
import { HelpDotIcon } from '../../internal/icons/16px';
import { ThemeContext } from '../../lib/theming/ThemeContext';
import { isFunction } from '../../lib/utils';
import { Tooltip } from '../Tooltip';
import { cx } from '../../lib/theming/Emotion';
import { TextareaDataTids, TextareaProps } from './Textarea';
import { styles } from './Textarea.styles';
export type TextareaCounterProps = {
value: TextareaProps['value'];
length: number;
help: TextareaProps['counterHelp'];
onCloseHelp: () => void;
textarea: HTMLTextAreaElement;
};
export interface TextareaCounterRef {
reflow: () => void;
}
const handleHelpMouseDown = (e: SyntheticEvent) => e.preventDefault();
export const TextareaCounter = forwardRefAndName<TextareaCounterRef, TextareaCounterProps>(
'TextareaCounter',
({ length, value, help, onCloseHelp, textarea }, ref) => {
const theme = useContext(ThemeContext);
const [width, setWidth] = useState(textarea.clientWidth);
const [height, setHeight] = useState(textarea.clientHeight);
const reflow = useCallback(() => {
const { clientWidth, clientHeight } = textarea;
setWidth(clientWidth);
setHeight(clientHeight);
}, [textarea]);
useImperativeHandle(ref, () => ({ reflow }), [reflow]);
const renderTooltipContent = useCallback(() => help, [help]);
const textareaValue = value ? value.toString().length : 0;
const counterValue = length - textareaValue;
const counterHelp = isFunction(help) ? (
help()
) : (
<Tooltip pos={'right bottom'} trigger={'click'} render={renderTooltipContent} onCloseClick={onCloseHelp}>
<HelpDotIcon onMouseDown={handleHelpMouseDown} color={theme.textareaCounterHelpIconColor} />
</Tooltip>
);
return (
<div data-tid={TextareaDataTids.counter} className={styles.counterContainer(theme)} style={{ width, height }}>
<span
className={cx(styles.counter(theme), {
[styles.counterError(theme)]: counterValue < 0,
})}
>
{counterValue}
{help && <span className={styles.counterHelp()}>{counterHelp}</span>}
</span>
</div>
);
},
);
TextareaCounter.propTypes = {
length: propTypes.number.isRequired,
value: propTypes.oneOfType([propTypes.string, propTypes.number]),
help: propTypes.oneOfType([propTypes.node, propTypes.func]),
onCloseHelp: propTypes.func.isRequired,
textarea: safePropTypesInstanceOf(() => HTMLElement).isRequired,
};