@kadconsulting/dry
Version:
KAD Reusable Component Library
122 lines • 6.29 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState, useEffect, useRef, forwardRef, useCallback, useMemo, } from 'react';
import { v4 as uuid } from 'uuid';
import useCopyToClipboard from '../../hooks/useCopyToClipboard';
import './Textarea.scss';
// import * as Utils from "./Textarea.utils.js";
import { Label as DryLabel } from '../TextInput/constituents/Label';
import classnames from 'classnames';
const Textarea = forwardRef(({ id, className, passProps, label, error, labelColor, ContainerProps, onFocus, onBlur, readOnly, disabled, lineNumbers, defaultText, tabHandling, richTextFormatting, asyncValidation, width, inputTextColor, inputBackgroundColor, required, LabelProps, labelRef, HintText, ...props }, ref) => {
const [textAreaId] = useState(() => id || `textarea-${uuid()}`);
const [textAreaValue, setTextAreaValue] = useState(defaultText || '');
const [lineCount, setLineCount] = useState(1);
const [asyncError, setAsyncError] = useState(null);
const textAreaRef = useRef(null);
const { copyToClipboard } = useCopyToClipboard();
const genStyle = () => {
const baseStyle = inputTextColor
? {
color: inputTextColor,
}
: {};
if (inputBackgroundColor) {
baseStyle.backgroundColor = inputBackgroundColor;
}
return baseStyle;
};
useEffect(() => {
if (textAreaRef.current && lineNumbers) {
const lineArray = textAreaValue.split('\n');
setLineCount(lineArray.length);
}
}, [textAreaValue, lineNumbers]);
const validateAsync = useCallback(async (value) => {
if (asyncValidation) {
const result = await asyncValidation(value);
setAsyncError(result);
}
}, [asyncValidation]);
const handleEvent = (event) => {
const value = event.target.value;
setTextAreaValue(value);
validateAsync(value);
};
const handleFocus = () => {
if (onFocus) {
onFocus();
}
};
const handleBlur = () => {
if (onBlur) {
onBlur();
}
if (!textAreaValue && defaultText) {
setTextAreaValue(defaultText);
}
};
const applyFormatting = (startTag, endTag) => {
const start = textAreaRef.current?.selectionStart;
const end = textAreaRef.current?.selectionEnd;
const selectedText = textAreaValue.substring(start || 0, end);
const beforeText = textAreaValue.substring(0, start);
const afterText = textAreaValue.substring(end || 0);
const formattedText = `${startTag}${selectedText}${endTag}`;
const newValue = `${beforeText}${formattedText}${afterText}`;
setTextAreaValue(newValue);
textAreaRef.current.selectionStart = (start || 0) + formattedText.length;
textAreaRef.current.selectionEnd = (start || 0) + formattedText.length;
};
const handleKeyDown = (e) => {
if (tabHandling && e.key === 'Tab') {
e.preventDefault();
const start = textAreaRef.current?.selectionStart;
const end = textAreaRef.current?.selectionEnd;
const value = textAreaValue;
const newValue = `${value.substring(0, start)}\t${value.substring(end || 0)}`;
setTextAreaValue(newValue);
}
if (richTextFormatting) {
if (e.ctrlKey && e.key === 'b') {
e.preventDefault();
applyFormatting('**', '**');
}
if (e.ctrlKey && e.key === 'i') {
e.preventDefault();
applyFormatting('_', '_');
}
}
};
const handleCut = (e) => {
if (richTextFormatting) {
const selectedText = window.getSelection()?.toString();
e.clipboardData.setData('text/plain', `Cut: ${selectedText}`);
copyToClipboard(`Cut: ${selectedText}`);
}
};
const handleCopy = (e) => {
if (richTextFormatting) {
const selectedText = window.getSelection()?.toString();
e.clipboardData.setData('text/plain', `Copy: ${selectedText}`);
copyToClipboard(`Copy: ${selectedText}`);
}
};
const handlePaste = async (e) => {
if (richTextFormatting) {
e.preventDefault();
const pastedData = e.clipboardData.getData('text/plain');
const modifiedData = `Pasted: ${pastedData}`;
const start = textAreaRef.current?.selectionStart;
const end = textAreaRef.current?.selectionEnd;
const value = textAreaValue;
const newValue = `${value.substring(0, start)}${modifiedData}${value.substring(end || 0)}`;
setTextAreaValue(newValue);
if (asyncValidation) {
await validateAsync(newValue);
}
}
};
const Label = useMemo(() => (_jsx(DryLabel, { required: required, labelColor: labelColor, htmlFor: textAreaId, ref: labelRef, className: classnames('dry-textarea__label', LabelProps?.className), ...LabelProps, children: label })), [label, LabelProps, textAreaId, labelRef, required, labelColor]);
return (_jsxs("div", { ref: ref, style: { width: typeof width === 'number' ? `${width}px` : width }, className: 'dry-textarea', ...ContainerProps, children: [Label, lineNumbers && (_jsx("div", { className: 'line-numbers', children: [...Array(lineCount)].map((_, i) => (_jsx("div", { className: 'line-number', children: i + 1 }, i))) })), _jsx("textarea", { className: `dry-textarea__input ${className}`, id: textAreaId, value: textAreaValue, onChange: handleEvent, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, onCut: handleCut, onCopy: handleCopy, onPaste: handlePaste, ref: textAreaRef, readOnly: readOnly, disabled: disabled, ...props, style: genStyle() }), HintText && _jsx("div", { className: 'dry-textarea__hint', children: HintText }), (error || asyncError) && (_jsx("p", { className: 'dry-textarea__error', children: error || asyncError })), inputTextColor && (_jsx("style", { children: ` .dry-textarea__input::placeholder {color: ${inputTextColor}; }` }))] }));
});
export default Textarea;
//# sourceMappingURL=Textarea.js.map