UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

373 lines (372 loc) 14.4 kB
"use strict"; "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