@helsenorge/designsystem-react 9.0.0-beta.3 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/Textarea.js +85 -83
- package/Textarea.js.map +1 -1
- package/components/Textarea/Textarea.d.ts +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## [8.8.0](https://github.com/helsenorge/designsystem/branchCompare?baseVersion=GTv8.7.0&targetVersion=GTv8.8.0) (2024-11-04)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **input:** eksponer inputmode som prop
|
|
6
|
+
([6bc9883](https://github.com/helsenorge/designsystem/commit/6bc98831c582f0356c04be50d9d3be1b4c65ba98)), closes
|
|
7
|
+
[#333385](https://github.com/helsenorge/designsystem/issues/333385)
|
|
8
|
+
- **textarea:** ny prop value ([fd9a116](https://github.com/helsenorge/designsystem/commit/fd9a11697229b87f88f135b8a5c16f7853cc9ead)),
|
|
9
|
+
closes [#335948](https://github.com/helsenorge/designsystem/issues/335948)
|
|
10
|
+
|
|
1
11
|
## [8.7.0](https://github.com/helsenorge/designsystem/branchCompare?baseVersion=GTv8.6.0&targetVersion=GTv8.7.0) (2024-10-17)
|
|
2
12
|
|
|
3
13
|
### Features
|
package/Textarea.js
CHANGED
|
@@ -1,111 +1,113 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import { FormOnColor as
|
|
5
|
-
import { useUuid as
|
|
6
|
-
import { getAriaDescribedBy as
|
|
7
|
-
import { u as
|
|
8
|
-
import { E as
|
|
9
|
-
import { a as
|
|
1
|
+
import { jsx as m, jsxs as te } from "react/jsx-runtime";
|
|
2
|
+
import ae, { useState as A, useRef as oe, useEffect as B } from "react";
|
|
3
|
+
import f from "classnames";
|
|
4
|
+
import { FormOnColor as p, AnalyticsId as ne, AVERAGE_CHARACTER_WIDTH_PX as ie } from "./constants.js";
|
|
5
|
+
import { useUuid as se } from "./hooks/useUuid.js";
|
|
6
|
+
import { getAriaDescribedBy as ce } from "./utils/accessibility.js";
|
|
7
|
+
import { u as de } from "./uuid.js";
|
|
8
|
+
import { E as le } from "./ErrorWrapper.js";
|
|
9
|
+
import { a as ue } from "./Label.js";
|
|
10
10
|
import { M as me } from "./MaxCharacters.js";
|
|
11
11
|
import r from "./components/Textarea/styles.module.scss";
|
|
12
|
-
const
|
|
12
|
+
const pe = (a) => `calc(${a * ie}px + 2rem + 16px + 4px)`, he = ae.forwardRef((a, b) => {
|
|
13
13
|
const {
|
|
14
14
|
maxCharacters: o,
|
|
15
|
-
maxText:
|
|
16
|
-
width:
|
|
17
|
-
testId:
|
|
15
|
+
maxText: g,
|
|
16
|
+
width: C,
|
|
17
|
+
testId: M,
|
|
18
18
|
defaultValue: i,
|
|
19
|
-
marginBottom:
|
|
20
|
-
transparent:
|
|
21
|
-
onColor: n =
|
|
22
|
-
label:
|
|
23
|
-
textareaId:
|
|
24
|
-
minRows:
|
|
19
|
+
marginBottom: $,
|
|
20
|
+
transparent: k,
|
|
21
|
+
onColor: n = p.onwhite,
|
|
22
|
+
label: D,
|
|
23
|
+
textareaId: w = de(),
|
|
24
|
+
minRows: T = 3,
|
|
25
25
|
maxRows: s = 10,
|
|
26
|
-
grow:
|
|
27
|
-
error:
|
|
28
|
-
errorText:
|
|
29
|
-
errorTextId:
|
|
30
|
-
errorWrapperClassName:
|
|
31
|
-
autoFocus:
|
|
32
|
-
disabled:
|
|
33
|
-
name:
|
|
34
|
-
autoComplete:
|
|
35
|
-
placeholder:
|
|
36
|
-
readOnly:
|
|
37
|
-
required:
|
|
38
|
-
onChange:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
A(()
|
|
42
|
-
|
|
26
|
+
grow: W,
|
|
27
|
+
error: L,
|
|
28
|
+
errorText: v,
|
|
29
|
+
errorTextId: S,
|
|
30
|
+
errorWrapperClassName: j,
|
|
31
|
+
autoFocus: F,
|
|
32
|
+
disabled: O,
|
|
33
|
+
name: U,
|
|
34
|
+
autoComplete: y = "off",
|
|
35
|
+
placeholder: V,
|
|
36
|
+
readOnly: q,
|
|
37
|
+
required: z,
|
|
38
|
+
onChange: R,
|
|
39
|
+
value: c,
|
|
40
|
+
...G
|
|
41
|
+
} = a, [P, E] = A(T), [h, d] = A(c || i || ""), l = oe(null), H = se(S);
|
|
42
|
+
B(() => {
|
|
43
|
+
d(i || "");
|
|
43
44
|
}, [i]);
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
e.rows =
|
|
45
|
+
const I = (e) => {
|
|
46
|
+
const u = e.rows;
|
|
47
|
+
e.rows = T;
|
|
47
48
|
const t = Math.floor((e.scrollHeight - 16) / 28);
|
|
48
|
-
t ===
|
|
49
|
-
},
|
|
50
|
-
[r["textarea--gutterBottom"]]:
|
|
51
|
-
}),
|
|
52
|
-
[r["input-container--transparent"]]:
|
|
53
|
-
[r["input-container--on-blueberry"]]:
|
|
54
|
-
[r["input-container--on-dark"]]:
|
|
55
|
-
[r["input-container--invalid"]]:
|
|
49
|
+
t === u && (e.rows = t), t >= s && (e.rows = s, e.scrollTop = e.scrollHeight), t < s ? E(t) : E(s);
|
|
50
|
+
}, X = n === p.ondark, J = n === p.onblueberry, K = !!o && h.toString().length > o, N = n === p.oninvalid || !!v || !!L || K, Q = f(r.textarea, {
|
|
51
|
+
[r["textarea--gutterBottom"]]: $
|
|
52
|
+
}), Y = f(r["input-container"], {
|
|
53
|
+
[r["input-container--transparent"]]: k,
|
|
54
|
+
[r["input-container--on-blueberry"]]: J,
|
|
55
|
+
[r["input-container--on-dark"]]: X,
|
|
56
|
+
[r["input-container--invalid"]]: N,
|
|
56
57
|
[r["input-container--disabled"]]: a.disabled
|
|
57
|
-
}),
|
|
58
|
+
}), Z = f(r["input-container__input"], {
|
|
58
59
|
[r["input-container__input--disabled"]]: a.disabled
|
|
59
60
|
});
|
|
60
|
-
|
|
61
|
-
var e,
|
|
62
|
-
if (
|
|
63
|
-
const t = (
|
|
64
|
-
|
|
61
|
+
B(() => {
|
|
62
|
+
var e, x, u;
|
|
63
|
+
if (c && d(c), W && ((e = l.current) != null && e.children) && ((x = l.current) != null && x.children[0])) {
|
|
64
|
+
const t = (u = l.current) == null ? void 0 : u.children[0];
|
|
65
|
+
I(t);
|
|
65
66
|
}
|
|
66
|
-
}, []);
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
},
|
|
72
|
-
return /* @__PURE__ */
|
|
73
|
-
|
|
74
|
-
/* @__PURE__ */
|
|
67
|
+
}, [c]);
|
|
68
|
+
const ee = (e) => {
|
|
69
|
+
W && I(e.target), d(e.target.value);
|
|
70
|
+
}, re = (e) => {
|
|
71
|
+
d(e.target.value), R && R(e), ee(e);
|
|
72
|
+
}, _ = C ? pe(C) : void 0;
|
|
73
|
+
return /* @__PURE__ */ m(le, { className: j, errorText: v, errorTextId: H, children: /* @__PURE__ */ te("div", { "data-testid": M, "data-analyticsid": ne.Textarea, className: Q, children: [
|
|
74
|
+
ue(D, w, n),
|
|
75
|
+
/* @__PURE__ */ m("div", { className: Y, ref: l, style: { maxWidth: _ }, children: /* @__PURE__ */ m(
|
|
75
76
|
"textarea",
|
|
76
77
|
{
|
|
77
|
-
|
|
78
|
+
...G,
|
|
79
|
+
rows: P,
|
|
78
80
|
defaultValue: i,
|
|
79
|
-
id:
|
|
80
|
-
className:
|
|
81
|
-
ref:
|
|
82
|
-
"aria-describedby":
|
|
83
|
-
"aria-invalid": !!
|
|
84
|
-
autoFocus:
|
|
85
|
-
disabled:
|
|
86
|
-
name:
|
|
87
|
-
autoComplete:
|
|
88
|
-
placeholder:
|
|
89
|
-
readOnly:
|
|
90
|
-
required:
|
|
91
|
-
onChange:
|
|
92
|
-
|
|
81
|
+
id: w,
|
|
82
|
+
className: Z,
|
|
83
|
+
ref: b,
|
|
84
|
+
"aria-describedby": ce(a, H),
|
|
85
|
+
"aria-invalid": !!N,
|
|
86
|
+
autoFocus: F,
|
|
87
|
+
disabled: O,
|
|
88
|
+
name: U,
|
|
89
|
+
autoComplete: y || void 0,
|
|
90
|
+
placeholder: V,
|
|
91
|
+
readOnly: q,
|
|
92
|
+
required: z,
|
|
93
|
+
onChange: re,
|
|
94
|
+
value: h
|
|
93
95
|
}
|
|
94
96
|
) }),
|
|
95
|
-
o && /* @__PURE__ */
|
|
97
|
+
o && /* @__PURE__ */ m(
|
|
96
98
|
me,
|
|
97
99
|
{
|
|
98
100
|
maxCharacters: o,
|
|
99
|
-
length:
|
|
100
|
-
maxText:
|
|
101
|
+
length: h.toString().length,
|
|
102
|
+
maxText: g,
|
|
101
103
|
onColor: n,
|
|
102
|
-
maxWidth:
|
|
104
|
+
maxWidth: _
|
|
103
105
|
}
|
|
104
106
|
)
|
|
105
107
|
] }) });
|
|
106
108
|
});
|
|
107
|
-
|
|
109
|
+
he.displayName = "Textarea";
|
|
108
110
|
export {
|
|
109
|
-
|
|
111
|
+
he as T
|
|
110
112
|
};
|
|
111
113
|
//# sourceMappingURL=Textarea.js.map
|
package/Textarea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.js","sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\nimport cn from 'classnames';\n\nimport { AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX, FormOnColor } from '../../constants';\nimport { useUuid } from '../../hooks/useUuid';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { uuid } from '../../utils/uuid';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport { renderLabel } from '../Label';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface TextareaProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLTextAreaElement>,\n | 'aria-describedby'\n | 'autoFocus'\n | 'disabled'\n | 'name'\n | 'autoComplete'\n | 'placeholder'\n | 'readOnly'\n | 'required'\n | 'defaultValue'\n | 'onChange'\n > {\n /** max character limit in textarea */\n maxCharacters?: number;\n /** The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Width of textarea in characters (approximate) */\n width?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** If true, the component will have a bottom margin. */\n marginBottom?: boolean;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Label of the input */\n label?: React.ReactNode;\n /** id of the textarea */\n textareaId?: string;\n /** max rows */\n maxRows?: number;\n /** min rows */\n minRows?: number;\n /** auto-grows until maxRows */\n grow?: boolean;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n}\n\nconst getTextareaMaxWidth = (characters: number): string => {\n const paddingWidth = '2rem';\n const scrollbarWidth = '16px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${scrollbarWidth} + ${borderWidth})`;\n};\n\nconst Textarea = React.forwardRef((props: TextareaProps, ref: React.Ref<HTMLTextAreaElement>) => {\n const {\n maxCharacters,\n maxText,\n width,\n testId,\n defaultValue,\n marginBottom: gutterBottom,\n transparent,\n onColor = FormOnColor.onwhite,\n label,\n textareaId = uuid(),\n minRows = 3,\n maxRows = 10,\n grow,\n error,\n errorText,\n errorTextId,\n errorWrapperClassName,\n autoFocus,\n disabled,\n name,\n autoComplete = 'off',\n placeholder,\n readOnly,\n required,\n onChange,\n ...rest\n } = props;\n\n const [rows, setRows] = useState(minRows);\n const [textareaInput, setTextareaInput] = useState(defaultValue || '');\n const referanse = useRef<HTMLDivElement>(null);\n const errorTextUuid = useUuid(errorTextId);\n\n useEffect(() => {\n setTextareaInput(defaultValue || '');\n }, [defaultValue]);\n\n const resizeHeight = (target: HTMLTextAreaElement): void => {\n const textareaLineHeight = 28;\n\n const previousRows = target.rows;\n target.rows = minRows; // reset number of rows in textarea\n\n const currentRows = Math.floor((target.scrollHeight - 16) / textareaLineHeight); // scrollHeight - 16px of padding to calculate the rows\n\n if (currentRows === previousRows) {\n target.rows = currentRows;\n }\n\n if (currentRows >= maxRows) {\n target.rows = maxRows;\n target.scrollTop = target.scrollHeight;\n }\n\n if (currentRows < maxRows) {\n setRows(currentRows);\n } else {\n setRows(maxRows);\n }\n };\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && textareaInput.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n\n const textareaWrapperClass = cn(styles.textarea, {\n [styles['textarea--gutterBottom']]: gutterBottom,\n });\n\n const contentWrapperClass = cn(styles['input-container'], {\n [styles['input-container--transparent']]: transparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: props.disabled,\n });\n\n const textareaClass = cn(styles['input-container__input'], {\n [styles[`input-container__input--disabled`]]: props.disabled,\n });\n\n useEffect(() => {\n if (grow && referanse.current?.children && referanse.current?.children[0]) {\n const textarea = referanse.current?.children[0] as HTMLTextAreaElement;\n resizeHeight(textarea);\n }\n }, []);\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n if (grow) {\n resizeHeight(e.target);\n }\n setTextareaInput(e.target.value);\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n if (onChange) {\n onChange(e);\n }\n handleChange(e);\n };\n\n const maxWidth = width ? getTextareaMaxWidth(width) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextUuid}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Textarea} className={textareaWrapperClass}>\n {renderLabel(label, textareaId, onColor as FormOnColor)}\n <div className={contentWrapperClass} ref={referanse} style={{ maxWidth }}>\n <textarea\n rows={rows}\n defaultValue={defaultValue}\n id={textareaId}\n className={textareaClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextUuid)}\n aria-invalid={!!onError}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n disabled={disabled}\n name={name}\n autoComplete={autoComplete ? autoComplete : undefined}\n placeholder={placeholder}\n readOnly={readOnly}\n required={required}\n onChange={onChangeHandler}\n {...rest}\n />\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={textareaInput.toString().length}\n maxText={maxText}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nTextarea.displayName = 'Textarea';\n\nexport default Textarea;\n"],"names":["getTextareaMaxWidth","characters","AVERAGE_CHARACTER_WIDTH_PX","Textarea","React","props","ref","maxCharacters","maxText","width","testId","defaultValue","gutterBottom","transparent","onColor","FormOnColor","label","textareaId","uuid","minRows","maxRows","grow","error","errorText","errorTextId","errorWrapperClassName","autoFocus","disabled","name","autoComplete","placeholder","readOnly","required","onChange","rest","rows","setRows","useState","textareaInput","setTextareaInput","referanse","useRef","errorTextUuid","useUuid","useEffect","resizeHeight","target","previousRows","currentRows","onDark","onBlueberry","maxCharactersExceeded","onError","textareaWrapperClass","cn","styles","contentWrapperClass","textareaClass","_a","_b","textarea","_c","handleChange","onChangeHandler","maxWidth","jsx","ErrorWrapper","jsxs","AnalyticsId","renderLabel","getAriaDescribedBy","MaxCharacters"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Textarea.js","sources":["../src/components/Textarea/Textarea.tsx"],"sourcesContent":["import React, { useState, useRef, useEffect } from 'react';\n\nimport cn from 'classnames';\n\nimport { AnalyticsId, AVERAGE_CHARACTER_WIDTH_PX, FormOnColor } from '../../constants';\nimport { useUuid } from '../../hooks/useUuid';\nimport { getAriaDescribedBy } from '../../utils/accessibility';\nimport { uuid } from '../../utils/uuid';\nimport ErrorWrapper, { ErrorWrapperClassNameProps } from '../ErrorWrapper';\nimport { renderLabel } from '../Label';\nimport MaxCharacters from '../MaxCharacters/MaxCharacters';\n\nimport styles from './styles.module.scss';\n\nexport interface TextareaProps\n extends ErrorWrapperClassNameProps,\n Pick<\n React.InputHTMLAttributes<HTMLTextAreaElement>,\n | 'aria-describedby'\n | 'autoFocus'\n | 'disabled'\n | 'name'\n | 'autoComplete'\n | 'placeholder'\n | 'readOnly'\n | 'required'\n | 'defaultValue'\n | 'onChange'\n | 'value'\n > {\n /** max character limit in textarea */\n maxCharacters?: number;\n /** The text is displayed in the end of the text-counter */\n maxText?: string;\n /** Width of textarea in characters (approximate) */\n width?: number;\n /** Sets the data-testid attribute. */\n testId?: string;\n /** If true, the component will have a bottom margin. */\n marginBottom?: boolean;\n /** If true, the component will be transparent. */\n transparent?: boolean;\n /** Changes the visuals of the textarea */\n onColor?: keyof typeof FormOnColor;\n /** Label of the input */\n label?: React.ReactNode;\n /** id of the textarea */\n textareaId?: string;\n /** max rows */\n maxRows?: number;\n /** min rows */\n minRows?: number;\n /** auto-grows until maxRows */\n grow?: boolean;\n /** Activates Error style for the input */\n error?: boolean;\n /** Error text to show above the component */\n errorText?: string;\n /** Error text id */\n errorTextId?: string;\n}\n\nconst getTextareaMaxWidth = (characters: number): string => {\n const paddingWidth = '2rem';\n const scrollbarWidth = '16px';\n const borderWidth = '4px';\n\n return `calc(${characters * AVERAGE_CHARACTER_WIDTH_PX}px + ${paddingWidth} + ${scrollbarWidth} + ${borderWidth})`;\n};\n\nconst Textarea = React.forwardRef((props: TextareaProps, ref: React.Ref<HTMLTextAreaElement>) => {\n const {\n maxCharacters,\n maxText,\n width,\n testId,\n defaultValue,\n marginBottom: gutterBottom,\n transparent,\n onColor = FormOnColor.onwhite,\n label,\n textareaId = uuid(),\n minRows = 3,\n maxRows = 10,\n grow,\n error,\n errorText,\n errorTextId,\n errorWrapperClassName,\n autoFocus,\n disabled,\n name,\n autoComplete = 'off',\n placeholder,\n readOnly,\n required,\n onChange,\n value,\n ...rest\n } = props;\n\n const [rows, setRows] = useState(minRows);\n const [textareaInput, setTextareaInput] = useState(value || defaultValue || '');\n const referanse = useRef<HTMLDivElement>(null);\n const errorTextUuid = useUuid(errorTextId);\n\n useEffect(() => {\n setTextareaInput(defaultValue || '');\n }, [defaultValue]);\n\n const resizeHeight = (target: HTMLTextAreaElement): void => {\n const textareaLineHeight = 28;\n\n const previousRows = target.rows;\n target.rows = minRows; // reset number of rows in textarea\n\n const currentRows = Math.floor((target.scrollHeight - 16) / textareaLineHeight); // scrollHeight - 16px of padding to calculate the rows\n\n if (currentRows === previousRows) {\n target.rows = currentRows;\n }\n\n if (currentRows >= maxRows) {\n target.rows = maxRows;\n target.scrollTop = target.scrollHeight;\n }\n\n if (currentRows < maxRows) {\n setRows(currentRows);\n } else {\n setRows(maxRows);\n }\n };\n\n const onDark = onColor === FormOnColor.ondark;\n const onBlueberry = onColor === FormOnColor.onblueberry;\n const maxCharactersExceeded = !!maxCharacters && textareaInput.toString().length > maxCharacters;\n const onError = onColor === FormOnColor.oninvalid || !!errorText || !!error || maxCharactersExceeded;\n\n const textareaWrapperClass = cn(styles.textarea, {\n [styles['textarea--gutterBottom']]: gutterBottom,\n });\n\n const contentWrapperClass = cn(styles['input-container'], {\n [styles['input-container--transparent']]: transparent,\n [styles['input-container--on-blueberry']]: onBlueberry,\n [styles['input-container--on-dark']]: onDark,\n [styles['input-container--invalid']]: onError,\n [styles['input-container--disabled']]: props.disabled,\n });\n\n const textareaClass = cn(styles['input-container__input'], {\n [styles[`input-container__input--disabled`]]: props.disabled,\n });\n\n useEffect(() => {\n value && setTextareaInput(value);\n\n if (grow && referanse.current?.children && referanse.current?.children[0]) {\n const textarea = referanse.current?.children[0] as HTMLTextAreaElement;\n resizeHeight(textarea);\n }\n }, [value]);\n\n const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n if (grow) {\n resizeHeight(e.target);\n }\n setTextareaInput(e.target.value);\n };\n\n const onChangeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {\n setTextareaInput(e.target.value);\n\n if (onChange) {\n onChange(e);\n }\n handleChange(e);\n };\n\n const maxWidth = width ? getTextareaMaxWidth(width) : undefined;\n\n return (\n <ErrorWrapper className={errorWrapperClassName} errorText={errorText} errorTextId={errorTextUuid}>\n <div data-testid={testId} data-analyticsid={AnalyticsId.Textarea} className={textareaWrapperClass}>\n {renderLabel(label, textareaId, onColor as FormOnColor)}\n <div className={contentWrapperClass} ref={referanse} style={{ maxWidth }}>\n <textarea\n {...rest}\n rows={rows}\n defaultValue={defaultValue}\n id={textareaId}\n className={textareaClass}\n ref={ref}\n aria-describedby={getAriaDescribedBy(props, errorTextUuid)}\n aria-invalid={!!onError}\n // eslint-disable-next-line jsx-a11y/no-autofocus\n autoFocus={autoFocus}\n disabled={disabled}\n name={name}\n autoComplete={autoComplete ? autoComplete : undefined}\n placeholder={placeholder}\n readOnly={readOnly}\n required={required}\n onChange={onChangeHandler}\n value={textareaInput}\n />\n </div>\n {maxCharacters && (\n <MaxCharacters\n maxCharacters={maxCharacters}\n length={textareaInput.toString().length}\n maxText={maxText}\n onColor={onColor}\n maxWidth={maxWidth}\n />\n )}\n </div>\n </ErrorWrapper>\n );\n});\n\nTextarea.displayName = 'Textarea';\n\nexport default Textarea;\n"],"names":["getTextareaMaxWidth","characters","AVERAGE_CHARACTER_WIDTH_PX","Textarea","React","props","ref","maxCharacters","maxText","width","testId","defaultValue","gutterBottom","transparent","onColor","FormOnColor","label","textareaId","uuid","minRows","maxRows","grow","error","errorText","errorTextId","errorWrapperClassName","autoFocus","disabled","name","autoComplete","placeholder","readOnly","required","onChange","value","rest","rows","setRows","useState","textareaInput","setTextareaInput","referanse","useRef","errorTextUuid","useUuid","useEffect","resizeHeight","target","previousRows","currentRows","onDark","onBlueberry","maxCharactersExceeded","onError","textareaWrapperClass","cn","styles","contentWrapperClass","textareaClass","_a","_b","textarea","_c","handleChange","onChangeHandler","maxWidth","jsx","ErrorWrapper","jsxs","AnalyticsId","renderLabel","getAriaDescribedBy","MaxCharacters"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { FormOnColor } from '../../constants';
|
|
3
3
|
import { ErrorWrapperClassNameProps } from '../ErrorWrapper';
|
|
4
|
-
export interface TextareaProps extends ErrorWrapperClassNameProps, Pick<React.InputHTMLAttributes<HTMLTextAreaElement>, 'aria-describedby' | 'autoFocus' | 'disabled' | 'name' | 'autoComplete' | 'placeholder' | 'readOnly' | 'required' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
export interface TextareaProps extends ErrorWrapperClassNameProps, Pick<React.InputHTMLAttributes<HTMLTextAreaElement>, 'aria-describedby' | 'autoFocus' | 'disabled' | 'name' | 'autoComplete' | 'placeholder' | 'readOnly' | 'required' | 'defaultValue' | 'onChange' | 'value'> {
|
|
5
5
|
/** max character limit in textarea */
|
|
6
6
|
maxCharacters?: number;
|
|
7
7
|
/** The text is displayed in the end of the text-counter */
|