@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
373 lines (372 loc) • 14.4 kB
JavaScript
;
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TextareaComponent = TextareaComponent;
exports.default = void 0;
var _withComponentMarkers = _interopRequireDefault(require("../../shared/helpers/withComponentMarkers.js"));
var _react = _interopRequireWildcard(require("react"));
var _useMountEffect = _interopRequireDefault(require("../../shared/helpers/useMountEffect.js"));
var _useCombinedRef = _interopRequireDefault(require("../../shared/helpers/useCombinedRef.js"));
var _clsx = _interopRequireDefault(require("clsx"));
var _FormLabel = _interopRequireDefault(require("../form-label/FormLabel.js"));
var _FormStatus = _interopRequireDefault(require("../form-status/FormStatus.js"));
var _TextCounter = _interopRequireDefault(require("../../fragments/text-counter/TextCounter.js"));
var _useId = _interopRequireDefault(require("../../shared/helpers/useId.js"));
var _componentHelper = require("../../shared/component-helper.js");
var _filterValidProps = require("../../shared/helpers/filterValidProps.js");
var _AlignmentHelper2 = _interopRequireDefault(require("../../shared/AlignmentHelper.js"));
var _SpacingUtils = require("../space/SpacingUtils.js");
var _SkeletonHelper = require("../skeleton/SkeletonHelper.js");
var _Context = _interopRequireDefault(require("../../shared/Context.js"));
var _Suffix = _interopRequireDefault(require("../../shared/helpers/Suffix.js"));
var _jsxRuntime = require("react/jsx-runtime");
var _AlignmentHelper, _span;
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const textareaDefaultProps = {
value: 'initval',
statusState: 'error',
readOnly: false,
labelDirection: 'vertical'
};
function hasValue(value) {
return (typeof value === 'string' || typeof value === 'number') && String(value).length > 0 || false;
}
function getValue(props) {
const value = (0, _componentHelper.processChildren)(props);
if (value === '' || hasValue(value)) {
return value;
}
return props.value;
}
function getResizeModifier() {
try {
if (typeof navigator !== 'undefined') {
if (/Firefox|Edg/.test(navigator.userAgent) || /Chrome/.test(navigator.userAgent) && /Win/.test(navigator.platform)) {
return 'large';
}
if (/Safari|Chrome/.test(navigator.userAgent) && /Mac/.test(navigator.platform)) {
return 'medium';
}
}
} catch (error) {
console.error(error);
}
return false;
}
function TextareaComponent({
ref,
...ownProps
}) {
var _context$getTranslati;
const context = (0, _react.useContext)(_Context.default);
const props = (0, _componentHelper.extendPropsWithContext)({
...textareaDefaultProps,
...(0, _componentHelper.removeUndefinedProps)({
...ownProps
})
}, textareaDefaultProps, {
skeleton: context === null || context === void 0 ? void 0 : context.skeleton
}, (_context$getTranslati = context.getTranslation(ownProps)) === null || _context$getTranslati === void 0 ? void 0 : _context$getTranslati.Textarea, (0, _filterValidProps.pickFormElementProps)(context === null || context === void 0 ? void 0 : context.formElement), context === null || context === void 0 ? void 0 : context.Textarea);
const {
label,
labelDirection,
labelSrOnly,
status,
statusState,
statusProps,
statusNoAnimation,
globalStatus,
suffix,
disabled,
skeleton,
stretch,
placeholder,
keepPlaceholder,
align,
size,
textareaClassName,
readOnly,
className,
autoResize,
characterCounter,
autoResizeMaxRows,
id: _id,
children: _children,
value: _value,
textareaElement: _textareaElement,
ref: _ref,
...attributes
} = props;
const textareaRef = (0, _react.useRef)(null);
const combinedRef = (0, _useCombinedRef.default)(ref, textareaRef);
const id = (0, _useId.default)(ownProps.id);
const resizeModifier = (0, _react.useMemo)(() => getResizeModifier(), []);
const heightOffsetRef = (0, _react.useRef)(undefined);
const resizeObserverRef = (0, _react.useRef)(null);
const propValue = getValue(ownProps);
const prevValuePropRef = (0, _react.useRef)(propValue);
const [value, setValue] = (0, _react.useState)(() => {
if (propValue !== 'initval' && propValue !== null) {
return propValue;
}
return null;
});
const [textareaState, setTextareaState] = (0, _react.useState)(() => {
return ownProps.textareaState || 'virgin';
});
if (propValue !== 'initval' && propValue !== value && propValue !== prevValuePropRef.current) {
setValue(propValue);
}
prevValuePropRef.current = propValue;
if (ownProps.textareaState && ownProps.textareaState !== textareaState) {
setTextareaState(ownProps.textareaState);
}
const getLineHeight = (0, _react.useCallback)(() => {
return parseFloat(getComputedStyle(textareaRef.current).lineHeight) || 0;
}, []);
const getRows = (0, _react.useCallback)(() => {
return Math.floor(textareaRef.current.scrollHeight / getLineHeight()) || 1;
}, [getLineHeight]);
const prepareAutosize = (0, _react.useCallback)(() => {
const elem = textareaRef.current;
if (!elem) {
return;
}
try {
elem.style.height = 'auto';
} catch (e) {
(0, _componentHelper.warn)(e);
}
}, []);
const setAutosize = (0, _react.useCallback)((rows = null) => {
const elem = textareaRef.current;
if (!elem) {
return;
}
try {
if (typeof heightOffsetRef.current === 'undefined') {
heightOffsetRef.current = elem.offsetHeight - elem.clientHeight;
}
elem.style.height = 'auto';
const lineHeight = getLineHeight();
let newHeight = elem.scrollHeight + heightOffsetRef.current;
if (!rows) {
rows = getRows();
}
if (rows === 1) {
if (newHeight > lineHeight) {
newHeight = lineHeight;
}
}
const maxRows = parseFloat(String(autoResizeMaxRows));
if (maxRows > 0) {
const maxHeight = maxRows * lineHeight;
if (rows > maxRows || newHeight > maxHeight) {
newHeight = maxHeight;
}
}
elem.style.height = newHeight + 'px';
} catch (e) {
(0, _componentHelper.warn)(e);
}
}, [autoResizeMaxRows, getLineHeight, getRows]);
const onFocusHandler = (0, _react.useCallback)(event => {
const {
value
} = textareaRef.current;
setValue(value);
setTextareaState('focus');
(0, _componentHelper.dispatchCustomElementEvent)(props, 'onFocus', {
value,
event
});
}, [props.onFocus]);
const onBlurHandler = (0, _react.useCallback)(event => {
const {
value
} = event.target;
setValue(value);
setTextareaState(hasValue(value) ? 'dirty' : 'initial');
(0, _componentHelper.dispatchCustomElementEvent)(props, 'onBlur', {
value,
event
});
}, [props.onBlur]);
const onChangeHandler = (0, _react.useCallback)(event => {
const {
value
} = event.target;
if (autoResize) {
prepareAutosize();
}
const rows = getRows();
const ret = (0, _componentHelper.dispatchCustomElementEvent)(props, 'onChange', {
value,
rows,
event
});
if (ret !== false) {
setValue(value);
if (autoResize) {
setAutosize(rows);
}
}
}, [autoResize, prepareAutosize, getRows, setAutosize, props.onChange]);
const onKeyDownHandler = (0, _react.useCallback)(event => {
const rows = getRows();
const {
value
} = event.target;
(0, _componentHelper.dispatchCustomElementEvent)(props, 'onKeyDown', {
value,
rows,
event
});
}, [getRows, props.onKeyDown]);
const setAutosizeRef = (0, _react.useRef)(setAutosize);
setAutosizeRef.current = setAutosize;
(0, _useMountEffect.default)(() => {
const handleResize = () => setAutosizeRef.current();
if (autoResize && typeof window !== 'undefined') {
setAutosizeRef.current();
try {
const observer = new ResizeObserver(entries => {
window.requestAnimationFrame(() => {
if (!Array.isArray(entries) || !entries.length) {
return;
}
setAutosizeRef.current();
});
});
observer.observe(document.body);
resizeObserverRef.current = observer;
} catch (e) {
window.addEventListener('resize', handleResize);
}
}
return () => {
if (resizeObserverRef.current) {
resizeObserverRef.current.disconnect();
resizeObserverRef.current = null;
}
if (typeof window !== 'undefined') {
window.removeEventListener('resize', handleResize);
}
};
});
const showStatus = (0, _componentHelper.getStatusState)(status);
const currentHasValue = hasValue(value);
let TextareaElement = props.textareaElement;
const textareaParams = {
className: (0, _clsx.default)("dnb-textarea__textarea dnb-input__border", textareaClassName),
role: 'textbox',
value: currentHasValue ? value : '',
id,
name: id,
disabled: disabled || skeleton,
'aria-placeholder': placeholder ? (0, _componentHelper.convertJsxToString)(placeholder) : undefined,
...attributes,
...(typeof size === 'number' ? {
size
} : {}),
onChange: onChangeHandler,
onFocus: onFocusHandler,
onBlur: onBlurHandler,
onKeyDown: onKeyDownHandler
};
if (showStatus || suffix) {
textareaParams['aria-describedby'] = (0, _componentHelper.combineDescribedBy)(textareaParams, showStatus ? id + '-status' : null, suffix ? id + '-suffix' : null);
}
if (readOnly) {
textareaParams['aria-readonly'] = textareaParams.readOnly = true;
}
const mainParams = (0, _SpacingUtils.applySpacing)(props, {
className: (0, _clsx.default)(`dnb-textarea dnb-textarea--${textareaState} dnb-form-component`, (0, _SkeletonHelper.createSkeletonClass)(null, skeleton), className, autoResize ? 'dnb-textarea__autoresize' : resizeModifier && `dnb-textarea__resize--${resizeModifier}`, disabled && 'dnb-textarea--disabled', currentHasValue && 'dnb-textarea--has-content', align && `dnb-textarea__align--${align}`, typeof size === 'string' && `dnb-textarea__size--${size}`, status && `dnb-textarea__status--${statusState}`, labelDirection && `dnb-textarea--${labelDirection}`, stretch && `dnb-textarea--stretch`, keepPlaceholder && `dnb-textarea--keep-placeholder`)
});
const innerParams = {
className: (0, _clsx.default)('dnb-textarea__inner', (0, _SkeletonHelper.createSkeletonClass)('shape', skeleton, context))
};
const shellParams = {
className: 'dnb-textarea__shell'
};
if (disabled || skeleton) {
shellParams['aria-disabled'] = true;
}
const placeholderStyle = parseFloat(String(props.rows)) > 0 ? {
'--textarea-rows': parseFloat(String(props.rows))
} : null;
(0, _SkeletonHelper.skeletonDOMAttributes)(innerParams, skeleton, context);
(0, _componentHelper.validateDOMAttributes)(ownProps, textareaParams);
(0, _componentHelper.validateDOMAttributes)(null, innerParams);
(0, _componentHelper.validateDOMAttributes)(null, shellParams);
if (TextareaElement && typeof TextareaElement === 'function') {
TextareaElement = TextareaElement(textareaParams, textareaRef);
} else if (!TextareaElement && _textareaElement) {
TextareaElement = _textareaElement;
}
return (0, _jsxRuntime.jsxs)("span", {
...mainParams,
children: [label && (0, _jsxRuntime.jsx)(_FormLabel.default, {
id: id + '-label',
forId: id,
text: label,
labelDirection: labelDirection,
srOnly: labelSrOnly,
disabled: disabled,
skeleton: skeleton
}), (0, _jsxRuntime.jsxs)("span", {
...innerParams,
children: [_AlignmentHelper || (_AlignmentHelper = (0, _jsxRuntime.jsx)(_AlignmentHelper2.default, {})), (0, _jsxRuntime.jsx)(_FormStatus.default, {
show: showStatus,
id: id + '-form-status',
globalStatus: globalStatus,
label: label,
textId: id + '-status',
text: status,
state: statusState,
noAnimation: statusNoAnimation,
skeleton: skeleton,
...statusProps
}), (0, _jsxRuntime.jsxs)("span", {
className: "dnb-textarea__row",
children: [(0, _jsxRuntime.jsxs)("span", {
...shellParams,
children: [TextareaElement || (0, _jsxRuntime.jsx)("textarea", {
ref: combinedRef,
...textareaParams
}), !currentHasValue && placeholder && (textareaState !== 'focus' || keepPlaceholder) && (0, _jsxRuntime.jsx)("span", {
className: 'dnb-textarea__placeholder' + (align ? ` dnb-textarea__align--${align}` : ""),
style: placeholderStyle,
"aria-hidden": true,
children: placeholder
}), _span || (_span = (0, _jsxRuntime.jsx)("span", {
className: "dnb-textarea__state"
}))]
}), suffix && (0, _jsxRuntime.jsx)(_Suffix.default, {
className: "dnb-textarea__suffix",
id: id + '-suffix',
context: props,
children: suffix
})]
}), characterCounter && (0, _jsxRuntime.jsx)(_TextCounter.default, {
top: "x-small",
text: value,
max: characterCounter,
lang: props.lang,
locale: props.locale,
...(typeof characterCounter === 'object' ? characterCounter : {})
})]
})]
});
}
TextareaComponent.displayName = 'Textarea';
const MemoizedTextarea = _react.default.memo(TextareaComponent);
(0, _withComponentMarkers.default)(MemoizedTextarea, {
_formElement: true,
_supportsSpacingProps: true
});
var _default = exports.default = MemoizedTextarea;
//# sourceMappingURL=Textarea.js.map