@dnb/eufemia
Version:
DNB Eufemia Design System UI Library
444 lines (443 loc) • 18.4 kB
JavaScript
"use strict";
"use client";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _parse = _interopRequireDefault(require("core-js-pure/stable/json/parse.js"));
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
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 _componentHelper = require("../../shared/component-helper.js");
var _filterValidProps = require("../../shared/helpers/filterValidProps.js");
var _AlignmentHelper2 = _interopRequireDefault(require("../../shared/AlignmentHelper.js"));
var _SpacingHelper = require("../space/SpacingHelper.js");
var _SkeletonHelper = require("../skeleton/SkeletonHelper.js");
var _Context = _interopRequireDefault(require("../../shared/Context.js"));
var _Suffix = _interopRequireDefault(require("../../shared/helpers/Suffix.js"));
var _AlignmentHelper, _span;
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
class Textarea extends _react.default.PureComponent {
static getDerivedStateFromProps(props, state) {
const value = Textarea.getValue(props);
if (value !== 'initval' && value !== state.value && value !== state._value) {
if (value !== state.value && typeof props.on_state_update === 'function') {
(0, _componentHelper.dispatchCustomElementEvent)({
props
}, 'on_state_update', {
value
});
}
state.value = value;
}
if (props.textarea_state) {
state.textareaState = props.textarea_state;
}
state._value = props.value;
return state;
}
static hasValue(value) {
return (typeof value === 'string' || typeof value === 'number') && String(value).length > 0 || false;
}
static getValue(props) {
const value = (0, _componentHelper.processChildren)(props);
if (value === '' || Textarea.hasValue(value)) {
return value;
}
return props.value;
}
constructor(_props) {
super(_props);
_defineProperty(this, "state", {
textareaState: 'virgin',
value: null,
_value: null
});
_defineProperty(this, "onFocusHandler", event => {
const {
value
} = this._ref.current;
this.setState({
value,
textareaState: 'focus'
});
(0, _componentHelper.dispatchCustomElementEvent)(this, 'on_focus', {
value,
event
});
});
_defineProperty(this, "onBlurHandler", event => {
const {
value
} = event.target;
this.setState({
value,
textareaState: Textarea.hasValue(value) ? 'dirty' : 'initial'
});
(0, _componentHelper.dispatchCustomElementEvent)(this, 'on_blur', {
value,
event
});
});
_defineProperty(this, "onChangeHandler", event => {
const {
value
} = event.target;
const props = this.getProps();
const autoresize = (0, _componentHelper.isTrue)(props.autoresize);
if (autoresize) {
this.prepareAutosize();
}
const rows = this.getRows(value);
const ret = (0, _componentHelper.dispatchCustomElementEvent)(this, 'on_change', {
value,
rows,
event
});
if (ret !== false) {
this.setState({
value
});
if (autoresize) {
this.setAutosize(rows);
}
}
});
_defineProperty(this, "onKeyDownHandler", event => {
const rows = this.getRows();
const {
value
} = event.target;
(0, _componentHelper.dispatchCustomElementEvent)(this, 'on_key_down', {
value,
rows,
event
});
});
_defineProperty(this, "prepareAutosize", () => {
const elem = this._ref.current;
if (!elem) {
return;
}
try {
elem.style.height = 'auto';
} catch (e) {
(0, _componentHelper.warn)(e);
}
});
_defineProperty(this, "setAutosize", (rows = null) => {
const elem = this._ref.current;
if (!elem) {
return;
}
try {
if (typeof this._heightOffset === 'undefined') {
this._heightOffset = elem.offsetHeight - elem.clientHeight;
}
elem.style.height = 'auto';
const lineHeight = this.getLineHeight();
let newHeight = elem.scrollHeight + this._heightOffset;
if (!rows) {
rows = this.getRows();
}
if (rows === 1) {
if (newHeight > lineHeight) {
newHeight = lineHeight;
}
}
const props = this.getProps();
const maxRows = parseFloat(props.autoresize_max_rows);
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);
}
});
this._ref = _react.default.createRef();
this._id = _props.id || (0, _componentHelper.makeUniqueId)();
if (_props.textarea_state) {
this.state.textareaState = _props.textarea_state;
}
try {
if (typeof navigator !== 'undefined') {
this.resizeModifier = /Firefox|Edg/.test(navigator.userAgent) || /Chrome/.test(navigator.userAgent) && /Win/.test(navigator.platform) ? 'large' : false;
if (!this.resizeModifier) {
this.resizeModifier = /Safari|Chrome/.test(navigator.userAgent) && /Mac/.test(navigator.platform) ? 'medium' : false;
}
}
} catch (error) {
console.error(error);
}
}
componentDidMount() {
const props = this.getProps();
if (props.inner_ref) {
typeof props.inner_ref === 'function' ? props.inner_ref(this._ref.current) : props.inner_ref.current = this._ref.current;
}
if ((0, _componentHelper.isTrue)(props.autoresize) && typeof window !== 'undefined') {
this.setAutosize();
try {
this.resizeObserver = new ResizeObserver(entries => {
window.requestAnimationFrame(() => {
if (!Array.isArray(entries) || !entries.length) {
return;
}
this.setAutosize();
});
});
this.resizeObserver.observe(document.body);
} catch (e) {
window.addEventListener('resize', this.setAutosize);
}
}
}
componentWillUnmount() {
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = null;
}
if (typeof window !== 'undefined') {
window.removeEventListener('resize', this.setAutosize);
}
}
getRows() {
return Math.floor(this._ref.current.scrollHeight / this.getLineHeight()) || 1;
}
getLineHeight() {
return parseFloat(getComputedStyle(this._ref.current).lineHeight) || 0;
}
getProps() {
var _this$context, _this$context2, _this$context3;
return (0, _componentHelper.extendPropsWithContextInClassComponent)(this.props, Textarea.defaultProps, {
skeleton: (_this$context = this.context) === null || _this$context === void 0 ? void 0 : _this$context.skeleton
}, this.context.getTranslation(this.props).Textarea, (0, _filterValidProps.pickFormElementProps)((_this$context2 = this.context) === null || _this$context2 === void 0 ? void 0 : _this$context2.FormRow), (0, _filterValidProps.pickFormElementProps)((_this$context3 = this.context) === null || _this$context3 === void 0 ? void 0 : _this$context3.formElement), this.context.Textarea);
}
render() {
const props = this.getProps();
const {
label,
label_direction,
label_sr_only,
status,
status_state,
status_props,
status_no_animation,
globalStatus,
suffix,
disabled,
skeleton,
stretch,
placeholder,
keepPlaceholder,
align,
size,
textarea_class,
readOnly,
textarea_attributes,
className,
autoresize,
characterCounter,
autoresize_max_rows,
id: _id,
children,
value: _value,
textarea_element: _textarea_element,
...attributes
} = props;
const {
value,
textareaState
} = this.state;
const id = this._id;
const showStatus = (0, _componentHelper.getStatusState)(status);
const hasValue = Textarea.hasValue(value);
let {
textarea_element: TextareaElement
} = props;
const textareaAttributes = textarea_attributes ? typeof textarea_attributes === 'string' ? (0, _parse.default)(textarea_attributes) : textarea_attributes : {};
const textareaParams = {
className: (0, _classnames.default)("dnb-textarea__textarea dnb-input__border", textarea_class),
role: 'textbox',
value: hasValue ? value : '',
id,
name: id,
disabled: (0, _componentHelper.isTrue)(disabled) || (0, _componentHelper.isTrue)(skeleton),
'aria-placeholder': placeholder ? (0, _componentHelper.convertJsxToString)(placeholder) : undefined,
...attributes,
...textareaAttributes,
onChange: this.onChangeHandler,
onFocus: this.onFocusHandler,
onBlur: this.onBlurHandler,
onKeyDown: this.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 = {
className: (0, _classnames.default)(`dnb-textarea dnb-textarea--${textareaState} dnb-form-component`, (0, _SkeletonHelper.createSkeletonClass)(null, skeleton), (0, _SpacingHelper.createSpacingClasses)(props), className, autoresize ? 'dnb-textarea__autoresize' : this.resizeModifier && `dnb-textarea__resize--${this.resizeModifier}`, disabled && 'dnb-textarea--disabled', hasValue && 'dnb-textarea--has-content', align && `dnb-textarea__align--${align}`, size && `dnb-textarea__size--${size}`, status && `dnb-textarea__status--${status_state}`, label_direction && `dnb-textarea--${label_direction}`, (0, _componentHelper.isTrue)(stretch) && `dnb-textarea--stretch`, (0, _componentHelper.isTrue)(keepPlaceholder) && `dnb-textarea--keep-placeholder`)
};
const innerParams = {
className: (0, _classnames.default)('dnb-textarea__inner', (0, _SkeletonHelper.createSkeletonClass)('shape', skeleton, this.context))
};
const shellParams = {
className: 'dnb-textarea__shell'
};
if ((0, _componentHelper.isTrue)(disabled) || (0, _componentHelper.isTrue)(skeleton)) {
shellParams['aria-disabled'] = true;
}
const placeholderStyle = parseFloat(props.rows) > 0 ? {
'--textarea-rows': parseFloat(props.rows)
} : null;
(0, _SkeletonHelper.skeletonDOMAttributes)(innerParams, skeleton, this.context);
(0, _componentHelper.validateDOMAttributes)(this.props, textareaParams);
(0, _componentHelper.validateDOMAttributes)(null, innerParams);
(0, _componentHelper.validateDOMAttributes)(null, shellParams);
if (TextareaElement && typeof TextareaElement === 'function') {
TextareaElement = TextareaElement(textareaParams, this._ref);
} else if (!TextareaElement && _textarea_element) {
TextareaElement = _textarea_element;
}
return _react.default.createElement("span", mainParams, label && _react.default.createElement(_FormLabel.default, {
id: id + '-label',
forId: id,
text: label,
labelDirection: label_direction,
srOnly: label_sr_only,
disabled: disabled,
skeleton: skeleton
}), _react.default.createElement("span", innerParams, _AlignmentHelper || (_AlignmentHelper = _react.default.createElement(_AlignmentHelper2.default, null)), _react.default.createElement(_FormStatus.default, _extends({
show: showStatus,
id: id + '-form-status',
globalStatus: globalStatus,
label: label,
text_id: id + '-status',
text: status,
state: status_state,
no_animation: status_no_animation,
skeleton: skeleton
}, status_props)), _react.default.createElement("span", {
className: "dnb-textarea__row"
}, _react.default.createElement("span", shellParams, TextareaElement || _react.default.createElement("textarea", _extends({
ref: this._ref
}, textareaParams)), !hasValue && placeholder && (textareaState !== 'focus' || keepPlaceholder) && _react.default.createElement("span", {
className: 'dnb-textarea__placeholder' + (align ? ` dnb-textarea__align--${align}` : ""),
style: placeholderStyle,
"aria-hidden": true
}, placeholder), _span || (_span = _react.default.createElement("span", {
className: "dnb-textarea__state"
}))), suffix && _react.default.createElement(_Suffix.default, {
className: "dnb-textarea__suffix",
id: id + '-suffix',
context: props
}, suffix)), characterCounter && _react.default.createElement(_TextCounter.default, _extends({
top: "x-small",
text: value,
max: characterCounter,
lang: props.lang,
locale: props.locale
}, characterCounter))));
}
}
exports.default = Textarea;
_defineProperty(Textarea, "contextType", _Context.default);
_defineProperty(Textarea, "defaultProps", {
value: 'initval',
id: null,
label: null,
label_direction: null,
label_sr_only: null,
status: null,
textarea_state: null,
status_state: 'error',
status_props: null,
status_no_animation: null,
globalStatus: null,
suffix: null,
placeholder: null,
keepPlaceholder: null,
align: null,
size: null,
stretch: null,
disabled: null,
skeleton: null,
autoresize: null,
autoresize_max_rows: null,
characterCounter: null,
textarea_class: null,
textarea_attributes: null,
readOnly: false,
rows: null,
cols: null,
inner_ref: null,
className: null,
textarea_element: null,
children: null,
on_change: null,
on_focus: null,
on_blur: null,
on_key_down: null,
on_state_update: null
});
process.env.NODE_ENV !== "production" ? Textarea.propTypes = {
value: _propTypes.default.string,
id: _propTypes.default.string,
label: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.node]),
label_direction: _propTypes.default.oneOf(['horizontal', 'vertical']),
label_sr_only: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
status: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool, _propTypes.default.func, _propTypes.default.node]),
textarea_state: _propTypes.default.string,
status_state: _propTypes.default.string,
status_props: _propTypes.default.object,
status_no_animation: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
globalStatus: _propTypes.default.shape({
id: _propTypes.default.string,
message: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.node])
}),
suffix: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.func, _propTypes.default.node]),
placeholder: _propTypes.default.node,
keepPlaceholder: _propTypes.default.bool,
align: _propTypes.default.oneOf(['left', 'right']),
size: _propTypes.default.oneOf(['small', 'medium', 'large']),
stretch: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
disabled: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
skeleton: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
characterCounter: _propTypes.default.oneOfType([_propTypes.default.shape({
max: _propTypes.default.number,
variant: _propTypes.default.oneOf(['down', 'up'])
}), _propTypes.default.number]),
autoresize: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
autoresize_max_rows: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.number]),
textarea_class: _propTypes.default.string,
textarea_attributes: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.object]),
readOnly: _propTypes.default.oneOfType([_propTypes.default.string, _propTypes.default.bool]),
rows: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
cols: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
inner_ref: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]),
..._SpacingHelper.spacingPropTypes,
className: _propTypes.default.string,
textarea_element: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.node]),
children: _propTypes.default.oneOfType([_propTypes.default.node, _propTypes.default.func]),
on_change: _propTypes.default.func,
on_focus: _propTypes.default.func,
on_blur: _propTypes.default.func,
on_key_down: _propTypes.default.func,
on_state_update: _propTypes.default.func
} : void 0;
Textarea._formElement = true;
Textarea._supportsSpacingProps = true;
//# sourceMappingURL=Textarea.js.map