@justeattakeaway/pie-textarea 0.7.0 → 0.8.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/custom-elements.json +59 -5
- package/dist/index.d.ts +19 -4
- package/dist/index.js +164 -129
- package/dist/react.d.ts +19 -4
- package/dist/react.js +11 -8
- package/package.json +2 -2
- package/src/defs.ts +13 -1
- package/src/index.ts +59 -18
- package/src/textarea.scss +43 -28
package/custom-elements.json
CHANGED
|
@@ -28,13 +28,21 @@
|
|
|
28
28
|
},
|
|
29
29
|
"default": "['auto', 'manual']"
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
"kind": "variable",
|
|
33
|
+
"name": "statusTypes",
|
|
34
|
+
"type": {
|
|
35
|
+
"text": "['default', 'success', 'error']"
|
|
36
|
+
},
|
|
37
|
+
"default": "['default', 'success', 'error']"
|
|
38
|
+
},
|
|
31
39
|
{
|
|
32
40
|
"kind": "variable",
|
|
33
41
|
"name": "defaultProps",
|
|
34
42
|
"type": {
|
|
35
43
|
"text": "DefaultProps"
|
|
36
44
|
},
|
|
37
|
-
"default": "{\n disabled: false,\n size: 'medium',\n resize: 'auto',\n label: '',\n value: '',\n autoFocus: false,\n readonly: false,\n required: false,\n}",
|
|
45
|
+
"default": "{\n disabled: false,\n size: 'medium',\n resize: 'auto',\n label: '',\n value: '',\n status: 'default',\n autoFocus: false,\n readonly: false,\n required: false,\n}",
|
|
38
46
|
"description": "Default values for optional properties that have default fallback values in the component."
|
|
39
47
|
}
|
|
40
48
|
],
|
|
@@ -55,6 +63,14 @@
|
|
|
55
63
|
"module": "src/defs.js"
|
|
56
64
|
}
|
|
57
65
|
},
|
|
66
|
+
{
|
|
67
|
+
"kind": "js",
|
|
68
|
+
"name": "statusTypes",
|
|
69
|
+
"declaration": {
|
|
70
|
+
"name": "statusTypes",
|
|
71
|
+
"module": "src/defs.js"
|
|
72
|
+
}
|
|
73
|
+
},
|
|
58
74
|
{
|
|
59
75
|
"kind": "js",
|
|
60
76
|
"name": "defaultProps",
|
|
@@ -150,11 +166,26 @@
|
|
|
150
166
|
"privacy": "public",
|
|
151
167
|
"attribute": "required"
|
|
152
168
|
},
|
|
169
|
+
{
|
|
170
|
+
"kind": "field",
|
|
171
|
+
"name": "status",
|
|
172
|
+
"privacy": "public",
|
|
173
|
+
"attribute": "status"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"kind": "field",
|
|
177
|
+
"name": "assistiveText",
|
|
178
|
+
"type": {
|
|
179
|
+
"text": "TextareaProps['assistiveText']"
|
|
180
|
+
},
|
|
181
|
+
"privacy": "public",
|
|
182
|
+
"attribute": "assistiveText"
|
|
183
|
+
},
|
|
153
184
|
{
|
|
154
185
|
"kind": "field",
|
|
155
186
|
"name": "name",
|
|
156
187
|
"type": {
|
|
157
|
-
"text": "TextareaProps['name']
|
|
188
|
+
"text": "TextareaProps['name']"
|
|
158
189
|
},
|
|
159
190
|
"privacy": "public",
|
|
160
191
|
"attribute": "name"
|
|
@@ -163,7 +194,7 @@
|
|
|
163
194
|
"kind": "field",
|
|
164
195
|
"name": "autocomplete",
|
|
165
196
|
"type": {
|
|
166
|
-
"text": "TextareaProps['autocomplete']
|
|
197
|
+
"text": "TextareaProps['autocomplete']"
|
|
167
198
|
},
|
|
168
199
|
"privacy": "public",
|
|
169
200
|
"attribute": "autocomplete"
|
|
@@ -176,6 +207,14 @@
|
|
|
176
207
|
},
|
|
177
208
|
"privacy": "private"
|
|
178
209
|
},
|
|
210
|
+
{
|
|
211
|
+
"kind": "field",
|
|
212
|
+
"name": "focusTarget",
|
|
213
|
+
"type": {
|
|
214
|
+
"text": "HTMLElement"
|
|
215
|
+
},
|
|
216
|
+
"privacy": "public"
|
|
217
|
+
},
|
|
179
218
|
{
|
|
180
219
|
"kind": "field",
|
|
181
220
|
"name": "_throttledResize",
|
|
@@ -272,6 +311,10 @@
|
|
|
272
311
|
}
|
|
273
312
|
}
|
|
274
313
|
]
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"kind": "method",
|
|
317
|
+
"name": "renderAssistiveText"
|
|
275
318
|
}
|
|
276
319
|
],
|
|
277
320
|
"events": [
|
|
@@ -337,17 +380,28 @@
|
|
|
337
380
|
"name": "required",
|
|
338
381
|
"fieldName": "required"
|
|
339
382
|
},
|
|
383
|
+
{
|
|
384
|
+
"name": "status",
|
|
385
|
+
"fieldName": "status"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"name": "assistiveText",
|
|
389
|
+
"type": {
|
|
390
|
+
"text": "TextareaProps['assistiveText']"
|
|
391
|
+
},
|
|
392
|
+
"fieldName": "assistiveText"
|
|
393
|
+
},
|
|
340
394
|
{
|
|
341
395
|
"name": "name",
|
|
342
396
|
"type": {
|
|
343
|
-
"text": "TextareaProps['name']
|
|
397
|
+
"text": "TextareaProps['name']"
|
|
344
398
|
},
|
|
345
399
|
"fieldName": "name"
|
|
346
400
|
},
|
|
347
401
|
{
|
|
348
402
|
"name": "autocomplete",
|
|
349
403
|
"type": {
|
|
350
|
-
"text": "TextareaProps['autocomplete']
|
|
404
|
+
"text": "TextareaProps['autocomplete']"
|
|
351
405
|
},
|
|
352
406
|
"fieldName": "autocomplete"
|
|
353
407
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { FormControlInterface } from '@justeattakeaway/pie-webc-core';
|
|
|
4
4
|
import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
|
|
5
5
|
import type { LitElement } from 'lit';
|
|
6
6
|
import type { nothing } from 'lit';
|
|
7
|
+
import type { PIEInputElement } from '@justeattakeaway/pie-webc-core';
|
|
7
8
|
import type { PropertyValues } from 'lit';
|
|
8
9
|
import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
|
|
9
10
|
import type { TemplateResult } from 'lit-html';
|
|
@@ -11,7 +12,7 @@ import type { TemplateResult } from 'lit-html';
|
|
|
11
12
|
/**
|
|
12
13
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
13
14
|
*/
|
|
14
|
-
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'defaultValue'>>;
|
|
15
|
+
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'assistiveText' | 'defaultValue'>>;
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -23,7 +24,7 @@ export declare const defaultProps: DefaultProps;
|
|
|
23
24
|
* @event {InputEvent} input - when the textarea value is changed.
|
|
24
25
|
* @event {CustomEvent} change - when the textarea value is changed.
|
|
25
26
|
*/
|
|
26
|
-
export declare class PieTextarea extends PieTextarea_base implements TextareaProps {
|
|
27
|
+
export declare class PieTextarea extends PieTextarea_base implements TextareaProps, PIEInputElement {
|
|
27
28
|
static shadowRootOptions: {
|
|
28
29
|
delegatesFocus: boolean;
|
|
29
30
|
mode: ShadowRootMode;
|
|
@@ -39,9 +40,12 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
39
40
|
readonly: boolean;
|
|
40
41
|
autoFocus: boolean;
|
|
41
42
|
required: boolean;
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
status: "default" | "error" | "success";
|
|
44
|
+
assistiveText: TextareaProps['assistiveText'];
|
|
45
|
+
name: TextareaProps['name'];
|
|
46
|
+
autocomplete: TextareaProps['autocomplete'];
|
|
44
47
|
private _textarea;
|
|
48
|
+
focusTarget: HTMLElement;
|
|
45
49
|
private _throttledResize;
|
|
46
50
|
/**
|
|
47
51
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -73,6 +77,7 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
73
77
|
private handleKeyDown;
|
|
74
78
|
disconnectedCallback(): void;
|
|
75
79
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
80
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
76
81
|
render(): TemplateResult<1>;
|
|
77
82
|
static styles: CSSResult;
|
|
78
83
|
}
|
|
@@ -83,6 +88,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
83
88
|
|
|
84
89
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
85
90
|
|
|
91
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
92
|
+
|
|
86
93
|
export declare interface TextareaProps {
|
|
87
94
|
/**
|
|
88
95
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -106,6 +113,14 @@ export declare interface TextareaProps {
|
|
|
106
113
|
* An optional default value to use when the textarea is reset.
|
|
107
114
|
*/
|
|
108
115
|
defaultValue?: string;
|
|
116
|
+
/**
|
|
117
|
+
* An optional assistive text to display below the textarea element. Must be provided when the status is success or error.
|
|
118
|
+
*/
|
|
119
|
+
assistiveText?: string;
|
|
120
|
+
/**
|
|
121
|
+
* The status of the textarea component / assistive text. Can be default, success or error.
|
|
122
|
+
*/
|
|
123
|
+
status?: typeof statusTypes[number];
|
|
109
124
|
/**
|
|
110
125
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
111
126
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,124 +1,127 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { LitElement as M, html as L, nothing as F, unsafeCSS as A } from "lit";
|
|
2
|
+
import { property as l, query as P } from "lit/decorators.js";
|
|
3
|
+
import { classMap as K } from "lit/directives/class-map.js";
|
|
4
|
+
import { ifDefined as b } from "lit/directives/if-defined.js";
|
|
5
|
+
import { live as G } from "lit/directives/live.js";
|
|
6
|
+
import "@justeattakeaway/pie-assistive-text";
|
|
6
7
|
import "@justeattakeaway/pie-form-label";
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
import { FormControlMixin as H, RtlMixin as U, wrapNativeEvent as X, validPropertyValues as O, defineCustomElement as J } from "@justeattakeaway/pie-webc-core";
|
|
9
|
+
var T = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
|
|
10
|
+
function Q(t) {
|
|
9
11
|
return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t;
|
|
10
12
|
}
|
|
11
|
-
var
|
|
12
|
-
return
|
|
13
|
+
var V = "Expected a function", R = 0 / 0, Y = "[object Symbol]", Z = /^\s+|\s+$/g, ee = /^[-+]0x[0-9a-f]+$/i, te = /^0b[01]+$/i, ae = /^0o[0-7]+$/i, re = parseInt, ie = typeof T == "object" && T && T.Object === Object && T, ne = typeof self == "object" && self && self.Object === Object && self, oe = ie || ne || Function("return this")(), se = Object.prototype, le = se.toString, de = Math.max, ce = Math.min, j = function() {
|
|
14
|
+
return oe.Date.now();
|
|
13
15
|
};
|
|
14
|
-
function
|
|
15
|
-
var r, i, u, d,
|
|
16
|
+
function ue(t, e, a) {
|
|
17
|
+
var r, i, h, u, d, p, x = 0, k = !1, v = !1, g = !0;
|
|
16
18
|
if (typeof t != "function")
|
|
17
|
-
throw new TypeError(
|
|
18
|
-
e =
|
|
19
|
-
function
|
|
20
|
-
var f = r,
|
|
21
|
-
return r = i = void 0,
|
|
19
|
+
throw new TypeError(V);
|
|
20
|
+
e = D(e) || 0, _(a) && (k = !!a.leading, v = "maxWait" in a, h = v ? de(D(a.maxWait) || 0, e) : h, g = "trailing" in a ? !!a.trailing : g);
|
|
21
|
+
function y(n) {
|
|
22
|
+
var f = r, z = i;
|
|
23
|
+
return r = i = void 0, x = n, u = t.apply(z, f), u;
|
|
22
24
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
25
|
+
function w(n) {
|
|
26
|
+
return x = n, d = setTimeout($, e), k ? y(n) : u;
|
|
25
27
|
}
|
|
26
|
-
function
|
|
27
|
-
var f = n - p,
|
|
28
|
-
return v ?
|
|
28
|
+
function q(n) {
|
|
29
|
+
var f = n - p, z = n - x, C = e - f;
|
|
30
|
+
return v ? ce(C, h - z) : C;
|
|
29
31
|
}
|
|
30
|
-
function
|
|
31
|
-
var f = n - p,
|
|
32
|
-
return p === void 0 || f >= e || f < 0 || v &&
|
|
32
|
+
function I(n) {
|
|
33
|
+
var f = n - p, z = n - x;
|
|
34
|
+
return p === void 0 || f >= e || f < 0 || v && z >= h;
|
|
33
35
|
}
|
|
34
|
-
function
|
|
35
|
-
var n =
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
38
|
-
|
|
36
|
+
function $() {
|
|
37
|
+
var n = j();
|
|
38
|
+
if (I(n))
|
|
39
|
+
return W(n);
|
|
40
|
+
d = setTimeout($, q(n));
|
|
39
41
|
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
42
|
+
function W(n) {
|
|
43
|
+
return d = void 0, g && r ? y(n) : (r = i = void 0, u);
|
|
42
44
|
}
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
+
function B() {
|
|
46
|
+
d !== void 0 && clearTimeout(d), x = 0, r = p = i = d = void 0;
|
|
45
47
|
}
|
|
46
|
-
function
|
|
47
|
-
return
|
|
48
|
+
function N() {
|
|
49
|
+
return d === void 0 ? u : W(j());
|
|
48
50
|
}
|
|
49
|
-
function
|
|
50
|
-
var n =
|
|
51
|
+
function S() {
|
|
52
|
+
var n = j(), f = I(n);
|
|
51
53
|
if (r = arguments, i = this, p = n, f) {
|
|
52
|
-
if (
|
|
53
|
-
return
|
|
54
|
+
if (d === void 0)
|
|
55
|
+
return w(p);
|
|
54
56
|
if (v)
|
|
55
|
-
return
|
|
57
|
+
return d = setTimeout($, e), y(p);
|
|
56
58
|
}
|
|
57
|
-
return
|
|
59
|
+
return d === void 0 && (d = setTimeout($, e)), u;
|
|
58
60
|
}
|
|
59
|
-
return
|
|
61
|
+
return S.cancel = B, S.flush = N, S;
|
|
60
62
|
}
|
|
61
|
-
function
|
|
63
|
+
function he(t, e, a) {
|
|
62
64
|
var r = !0, i = !0;
|
|
63
65
|
if (typeof t != "function")
|
|
64
|
-
throw new TypeError(
|
|
65
|
-
return
|
|
66
|
+
throw new TypeError(V);
|
|
67
|
+
return _(a) && (r = "leading" in a ? !!a.leading : r, i = "trailing" in a ? !!a.trailing : i), ue(t, e, {
|
|
66
68
|
leading: r,
|
|
67
69
|
maxWait: e,
|
|
68
70
|
trailing: i
|
|
69
71
|
});
|
|
70
72
|
}
|
|
71
|
-
function
|
|
73
|
+
function _(t) {
|
|
72
74
|
var e = typeof t;
|
|
73
75
|
return !!t && (e == "object" || e == "function");
|
|
74
76
|
}
|
|
75
|
-
function
|
|
77
|
+
function pe(t) {
|
|
76
78
|
return !!t && typeof t == "object";
|
|
77
79
|
}
|
|
78
|
-
function
|
|
79
|
-
return typeof t == "symbol" ||
|
|
80
|
+
function fe(t) {
|
|
81
|
+
return typeof t == "symbol" || pe(t) && le.call(t) == Y;
|
|
80
82
|
}
|
|
81
|
-
function
|
|
83
|
+
function D(t) {
|
|
82
84
|
if (typeof t == "number")
|
|
83
85
|
return t;
|
|
84
|
-
if (
|
|
85
|
-
return
|
|
86
|
-
if (
|
|
86
|
+
if (fe(t))
|
|
87
|
+
return R;
|
|
88
|
+
if (_(t)) {
|
|
87
89
|
var e = typeof t.valueOf == "function" ? t.valueOf() : t;
|
|
88
|
-
t =
|
|
90
|
+
t = _(e) ? e + "" : e;
|
|
89
91
|
}
|
|
90
92
|
if (typeof t != "string")
|
|
91
93
|
return t === 0 ? t : +t;
|
|
92
|
-
t = t.replace(
|
|
93
|
-
var a =
|
|
94
|
-
return a ||
|
|
94
|
+
t = t.replace(Z, "");
|
|
95
|
+
var a = te.test(t);
|
|
96
|
+
return a || ae.test(t) ? re(t.slice(2), a ? 2 : 8) : ee.test(t) ? R : +t;
|
|
95
97
|
}
|
|
96
|
-
var
|
|
97
|
-
const
|
|
98
|
-
`,
|
|
98
|
+
var xe = he;
|
|
99
|
+
const ve = /* @__PURE__ */ Q(xe), ge = `*,*:after,*:before{box-sizing:inherit}.c-textareaWrapper{--textarea-line-height: calc(var(--dt-font-body-l-line-height) * 1px);--textarea-border-thickness: 1px;--textarea-resize: none;--textarea-padding-inline: var(--dt-spacing-c);--textarea-padding-block: var(--dt-spacing-b);--textarea-background-color: var(--dt-color-container-default);--textarea-border-color: var(--dt-color-interactive-form);--textarea-content-color: var(--dt-color-content-default);--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2));line-height:0;padding:var(--dt-spacing-a);border:var(--textarea-border-thickness) solid var(--textarea-border-color);background-color:var(--textarea-background-color);border-radius:var(--dt-radius-rounded-c);inline-size:100%}.c-textareaWrapper textarea{font-size:calc(var(--dt-font-body-l-size) * 1px);line-height:var(--textarea-line-height);font-family:var(--dt-font-body-l-family);resize:var(--textarea-resize);border:none;background-color:var(--textarea-background-color);color:var(--textarea-content-color);block-size:var(--textarea-height);max-block-size:var(--textarea-max-height);min-block-size:var(--textarea-min-height);inline-size:100%;padding-block-start:var(--textarea-padding-block);padding-block-end:var(--textarea-padding-block);padding-inline-start:var(--textarea-padding-inline);padding-inline-end:var(--textarea-padding-inline)}.c-textareaWrapper textarea:focus{box-shadow:none;outline:none}.c-textareaWrapper.c-textarea--disabled{--textarea-background-color: var(--dt-color-disabled-01);--textarea-border-color: var(--dt-color-disabled-01);--textarea-content-color: var(--dt-color-content-disabled)}@media (hover: hover){.c-textareaWrapper:hover:not(.c-textarea--disabled){--textarea-background-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + calc(-1 * var(--dt-color-hover-01))))}}.c-textareaWrapper:focus-within{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.c-textareaWrapper.c-textarea--large{--textarea-padding-block: var(--dt-spacing-c)}.c-textareaWrapper.c-textarea--small{--textarea-padding-block: var(--dt-spacing-a)}.c-textareaWrapper.c-textarea--resize-manual{--textarea-resize: vertical;--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2))}@media (pointer: coarse){.c-textareaWrapper.c-textarea--resize-manual{--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));--textarea-resize: none}}.c-textareaWrapper.c-textarea--resize-auto{--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));--textarea-min-height: var(--textarea-height)}.c-textareaWrapper.c-textarea--error{--textarea-border-color: var(--dt-color-support-error)}
|
|
100
|
+
`, me = ["small", "medium", "large"], be = ["auto", "manual"], ye = ["default", "success", "error"], c = {
|
|
99
101
|
disabled: !1,
|
|
100
102
|
size: "medium",
|
|
101
103
|
resize: "auto",
|
|
102
104
|
label: "",
|
|
103
105
|
value: "",
|
|
106
|
+
status: "default",
|
|
104
107
|
autoFocus: !1,
|
|
105
108
|
readonly: !1,
|
|
106
109
|
required: !1
|
|
107
110
|
};
|
|
108
|
-
var
|
|
109
|
-
for (var i = r > 1 ? void 0 : r ?
|
|
110
|
-
(
|
|
111
|
-
return r && i &&
|
|
111
|
+
var ze = Object.defineProperty, ke = Object.getOwnPropertyDescriptor, s = (t, e, a, r) => {
|
|
112
|
+
for (var i = r > 1 ? void 0 : r ? ke(e, a) : e, h = t.length - 1, u; h >= 0; h--)
|
|
113
|
+
(u = t[h]) && (i = (r ? u(e, a, i) : u(i)) || i);
|
|
114
|
+
return r && i && ze(e, a, i), i;
|
|
112
115
|
};
|
|
113
|
-
const
|
|
114
|
-
class o extends
|
|
116
|
+
const m = "pie-textarea", E = "assistive-text";
|
|
117
|
+
class o extends H(U(M)) {
|
|
115
118
|
constructor() {
|
|
116
|
-
super(...arguments), this.value =
|
|
117
|
-
this.resize === "auto" && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight
|
|
119
|
+
super(...arguments), this.value = c.value, this.disabled = c.disabled, this.size = c.size, this.resize = c.resize, this.label = c.label, this.readonly = c.readonly, this.autoFocus = c.autoFocus, this.required = c.required, this.status = c.status, this._throttledResize = ve(() => {
|
|
120
|
+
this.resize === "auto" && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight}px`);
|
|
118
121
|
}, 100), this.handleInput = (e) => {
|
|
119
122
|
this.value = e.target.value, this.restrictInputLength(), this._internals.setFormValue(this.value), this.handleResize();
|
|
120
123
|
}, this.handleChange = (e) => {
|
|
121
|
-
const a =
|
|
124
|
+
const a = X(e);
|
|
122
125
|
this.dispatchEvent(a);
|
|
123
126
|
}, this.handleKeyDown = (e) => {
|
|
124
127
|
e.key === "Enter" && e.stopPropagation();
|
|
@@ -145,10 +148,10 @@ class o extends K(G(w)) {
|
|
|
145
148
|
* Resets the value to the default value.
|
|
146
149
|
*/
|
|
147
150
|
formResetCallback() {
|
|
148
|
-
this.value = this.defaultValue ??
|
|
151
|
+
this.value = this.defaultValue ?? c.value, this._internals.setFormValue(this.value);
|
|
149
152
|
}
|
|
150
153
|
firstUpdated() {
|
|
151
|
-
this.restrictInputLength(), this._internals.setFormValue(this.value), this._textarea.addEventListener("keydown", this.handleKeyDown);
|
|
154
|
+
this.restrictInputLength(), this._internals.setFormValue(this.value), window.addEventListener("resize", () => this.handleResize()), this._textarea.addEventListener("keydown", this.handleKeyDown);
|
|
152
155
|
}
|
|
153
156
|
handleResize() {
|
|
154
157
|
this._throttledResize();
|
|
@@ -163,11 +166,21 @@ class o extends K(G(w)) {
|
|
|
163
166
|
e.has("value") && (this.restrictInputLength(), this._internals.setFormValue(this.value)), this.resize === "auto" && (e.has("resize") || e.has("size")) && this.handleResize();
|
|
164
167
|
}
|
|
165
168
|
disconnectedCallback() {
|
|
166
|
-
this._textarea.removeEventListener("keydown", this.handleKeyDown);
|
|
169
|
+
this._textarea.removeEventListener("keydown", this.handleKeyDown), window.removeEventListener("resize", () => this.handleResize());
|
|
167
170
|
}
|
|
168
171
|
renderLabel(e, a) {
|
|
169
172
|
const r = a ? `${this.value.length}/${a}` : void 0;
|
|
170
|
-
return e != null && e.length ?
|
|
173
|
+
return e != null && e.length ? L`<pie-form-label for="${m}" trailing=${b(r)}>${e}</pie-form-label>` : F;
|
|
174
|
+
}
|
|
175
|
+
renderAssistiveText() {
|
|
176
|
+
return this.assistiveText ? L`
|
|
177
|
+
<pie-assistive-text
|
|
178
|
+
id="${E}"
|
|
179
|
+
variant=${b(this.status)}
|
|
180
|
+
data-test-id="pie-textarea-assistive-text">
|
|
181
|
+
${this.assistiveText}
|
|
182
|
+
</pie-assistive-text>
|
|
183
|
+
` : F;
|
|
171
184
|
}
|
|
172
185
|
render() {
|
|
173
186
|
const {
|
|
@@ -175,84 +188,106 @@ class o extends K(G(w)) {
|
|
|
175
188
|
resize: a,
|
|
176
189
|
size: r,
|
|
177
190
|
autocomplete: i,
|
|
178
|
-
autoFocus:
|
|
179
|
-
name:
|
|
180
|
-
readonly:
|
|
191
|
+
autoFocus: h,
|
|
192
|
+
name: u,
|
|
193
|
+
readonly: d,
|
|
181
194
|
value: p,
|
|
182
|
-
required:
|
|
183
|
-
label:
|
|
184
|
-
maxLength: v
|
|
185
|
-
|
|
186
|
-
|
|
195
|
+
required: x,
|
|
196
|
+
label: k,
|
|
197
|
+
maxLength: v,
|
|
198
|
+
status: g,
|
|
199
|
+
assistiveText: y
|
|
200
|
+
} = this, w = {
|
|
201
|
+
"c-textareaWrapper": !0,
|
|
202
|
+
"c-textarea--disabled": e,
|
|
203
|
+
"c-textarea--error": g === "error",
|
|
204
|
+
[`c-textarea--resize-${a}`]: !0,
|
|
205
|
+
[`c-textarea--${r}`]: !0
|
|
206
|
+
};
|
|
207
|
+
return L`<div>
|
|
208
|
+
${this.renderLabel(k, v)}
|
|
187
209
|
<div
|
|
188
|
-
class="
|
|
189
|
-
data-test-id="pie-textarea-wrapper"
|
|
190
|
-
data-pie-size="${r}"
|
|
191
|
-
data-pie-resize="${a}">
|
|
192
|
-
${this.renderLabel(m, v)}
|
|
210
|
+
class="${K(w)}"
|
|
211
|
+
data-test-id="pie-textarea-wrapper">
|
|
193
212
|
<textarea
|
|
194
|
-
id="${
|
|
195
|
-
data-test-id="${
|
|
196
|
-
name=${
|
|
197
|
-
autocomplete=${
|
|
198
|
-
.value=${
|
|
199
|
-
?autofocus=${
|
|
200
|
-
?readonly=${
|
|
201
|
-
?required=${
|
|
213
|
+
id="${m}"
|
|
214
|
+
data-test-id="${m}"
|
|
215
|
+
name=${b(u)}
|
|
216
|
+
autocomplete=${b(i)}
|
|
217
|
+
.value=${G(p)}
|
|
218
|
+
?autofocus=${h}
|
|
219
|
+
?readonly=${d}
|
|
220
|
+
?required=${x}
|
|
202
221
|
?disabled=${e}
|
|
222
|
+
aria-describedby=${b(y ? E : void 0)}
|
|
223
|
+
aria-invalid=${g === "error" ? "true" : "false"}
|
|
224
|
+
aria-errormessage="${b(g === "error" ? E : void 0)}"
|
|
203
225
|
@input=${this.handleInput}
|
|
204
226
|
@change=${this.handleChange}
|
|
205
227
|
></textarea>
|
|
206
|
-
</div
|
|
228
|
+
</div>
|
|
229
|
+
${this.renderAssistiveText()}
|
|
230
|
+
</div>`;
|
|
207
231
|
}
|
|
208
232
|
}
|
|
209
|
-
o.shadowRootOptions = { ...
|
|
210
|
-
o.styles =
|
|
211
|
-
|
|
212
|
-
|
|
233
|
+
o.shadowRootOptions = { ...M.shadowRootOptions, delegatesFocus: !0 };
|
|
234
|
+
o.styles = A(ge);
|
|
235
|
+
s([
|
|
236
|
+
l({ type: String })
|
|
213
237
|
], o.prototype, "value", 2);
|
|
214
|
-
|
|
215
|
-
|
|
238
|
+
s([
|
|
239
|
+
l({ type: String })
|
|
216
240
|
], o.prototype, "defaultValue", 2);
|
|
217
|
-
|
|
218
|
-
|
|
241
|
+
s([
|
|
242
|
+
l({ type: Boolean, reflect: !0 })
|
|
219
243
|
], o.prototype, "disabled", 2);
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
244
|
+
s([
|
|
245
|
+
l({ type: String }),
|
|
246
|
+
O(m, me, c.size)
|
|
223
247
|
], o.prototype, "size", 2);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
248
|
+
s([
|
|
249
|
+
l({ type: String }),
|
|
250
|
+
O(m, be, c.resize)
|
|
227
251
|
], o.prototype, "resize", 2);
|
|
228
|
-
|
|
229
|
-
|
|
252
|
+
s([
|
|
253
|
+
l({ type: String })
|
|
230
254
|
], o.prototype, "label", 2);
|
|
231
|
-
|
|
232
|
-
|
|
255
|
+
s([
|
|
256
|
+
l({ type: Number })
|
|
233
257
|
], o.prototype, "maxLength", 2);
|
|
234
|
-
|
|
235
|
-
|
|
258
|
+
s([
|
|
259
|
+
l({ type: Boolean })
|
|
236
260
|
], o.prototype, "readonly", 2);
|
|
237
|
-
|
|
238
|
-
|
|
261
|
+
s([
|
|
262
|
+
l({ type: Boolean })
|
|
239
263
|
], o.prototype, "autoFocus", 2);
|
|
240
|
-
|
|
241
|
-
|
|
264
|
+
s([
|
|
265
|
+
l({ type: Boolean })
|
|
242
266
|
], o.prototype, "required", 2);
|
|
243
|
-
|
|
244
|
-
|
|
267
|
+
s([
|
|
268
|
+
l({ type: String }),
|
|
269
|
+
O(m, ye, c.status)
|
|
270
|
+
], o.prototype, "status", 2);
|
|
271
|
+
s([
|
|
272
|
+
l({ type: String })
|
|
273
|
+
], o.prototype, "assistiveText", 2);
|
|
274
|
+
s([
|
|
275
|
+
l({ type: String })
|
|
245
276
|
], o.prototype, "name", 2);
|
|
246
|
-
|
|
247
|
-
|
|
277
|
+
s([
|
|
278
|
+
l({ type: String })
|
|
248
279
|
], o.prototype, "autocomplete", 2);
|
|
249
|
-
|
|
250
|
-
|
|
280
|
+
s([
|
|
281
|
+
P("textarea")
|
|
251
282
|
], o.prototype, "_textarea", 2);
|
|
252
|
-
|
|
283
|
+
s([
|
|
284
|
+
P("textarea")
|
|
285
|
+
], o.prototype, "focusTarget", 2);
|
|
286
|
+
J(m, o);
|
|
253
287
|
export {
|
|
254
288
|
o as PieTextarea,
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
289
|
+
c as defaultProps,
|
|
290
|
+
be as resizeModes,
|
|
291
|
+
me as sizes,
|
|
292
|
+
ye as statusTypes
|
|
258
293
|
};
|
package/dist/react.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { FormControlInterface } from '@justeattakeaway/pie-webc-core';
|
|
|
4
4
|
import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
|
|
5
5
|
import type { LitElement } from 'lit';
|
|
6
6
|
import type { nothing } from 'lit';
|
|
7
|
+
import type { PIEInputElement } from '@justeattakeaway/pie-webc-core';
|
|
7
8
|
import type { PropertyValues } from 'lit';
|
|
8
9
|
import * as React_2 from 'react';
|
|
9
10
|
import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
|
|
@@ -12,7 +13,7 @@ import type { TemplateResult } from 'lit-html';
|
|
|
12
13
|
/**
|
|
13
14
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
14
15
|
*/
|
|
15
|
-
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'defaultValue'>>;
|
|
16
|
+
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'assistiveText' | 'defaultValue'>>;
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -26,7 +27,7 @@ export declare const PieTextarea: React_2.ForwardRefExoticComponent<TextareaProp
|
|
|
26
27
|
* @event {InputEvent} input - when the textarea value is changed.
|
|
27
28
|
* @event {CustomEvent} change - when the textarea value is changed.
|
|
28
29
|
*/
|
|
29
|
-
declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
30
|
+
declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps, PIEInputElement {
|
|
30
31
|
static shadowRootOptions: {
|
|
31
32
|
delegatesFocus: boolean;
|
|
32
33
|
mode: ShadowRootMode;
|
|
@@ -42,9 +43,12 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
42
43
|
readonly: boolean;
|
|
43
44
|
autoFocus: boolean;
|
|
44
45
|
required: boolean;
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
status: "default" | "error" | "success";
|
|
47
|
+
assistiveText: TextareaProps['assistiveText'];
|
|
48
|
+
name: TextareaProps['name'];
|
|
49
|
+
autocomplete: TextareaProps['autocomplete'];
|
|
47
50
|
private _textarea;
|
|
51
|
+
focusTarget: HTMLElement;
|
|
48
52
|
private _throttledResize;
|
|
49
53
|
/**
|
|
50
54
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -76,6 +80,7 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
76
80
|
private handleKeyDown;
|
|
77
81
|
disconnectedCallback(): void;
|
|
78
82
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
83
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
79
84
|
render(): TemplateResult<1>;
|
|
80
85
|
static styles: CSSResult;
|
|
81
86
|
}
|
|
@@ -93,6 +98,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
93
98
|
|
|
94
99
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
95
100
|
|
|
101
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
102
|
+
|
|
96
103
|
export declare interface TextareaProps {
|
|
97
104
|
/**
|
|
98
105
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -116,6 +123,14 @@ export declare interface TextareaProps {
|
|
|
116
123
|
* An optional default value to use when the textarea is reset.
|
|
117
124
|
*/
|
|
118
125
|
defaultValue?: string;
|
|
126
|
+
/**
|
|
127
|
+
* An optional assistive text to display below the textarea element. Must be provided when the status is success or error.
|
|
128
|
+
*/
|
|
129
|
+
assistiveText?: string;
|
|
130
|
+
/**
|
|
131
|
+
* The status of the textarea component / assistive text. Can be default, success or error.
|
|
132
|
+
*/
|
|
133
|
+
status?: typeof statusTypes[number];
|
|
119
134
|
/**
|
|
120
135
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
121
136
|
*/
|
package/dist/react.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import * as e from "react";
|
|
2
2
|
import { createComponent as t } from "@lit/react";
|
|
3
3
|
import { PieTextarea as a } from "./index.js";
|
|
4
|
-
import { defaultProps as
|
|
4
|
+
import { defaultProps as d, resizeModes as g, sizes as C, statusTypes as h } from "./index.js";
|
|
5
5
|
import "lit";
|
|
6
6
|
import "lit/decorators.js";
|
|
7
|
-
import "lit/directives/
|
|
8
|
-
import "@justeattakeaway/pie-webc-core";
|
|
7
|
+
import "lit/directives/class-map.js";
|
|
9
8
|
import "lit/directives/if-defined.js";
|
|
9
|
+
import "lit/directives/live.js";
|
|
10
|
+
import "@justeattakeaway/pie-assistive-text";
|
|
10
11
|
import "@justeattakeaway/pie-form-label";
|
|
12
|
+
import "@justeattakeaway/pie-webc-core";
|
|
11
13
|
const r = t({
|
|
12
14
|
displayName: "PieTextarea",
|
|
13
15
|
elementClass: a,
|
|
@@ -19,10 +21,11 @@ const r = t({
|
|
|
19
21
|
onChange: "change"
|
|
20
22
|
// when the textarea value is changed.
|
|
21
23
|
}
|
|
22
|
-
}),
|
|
24
|
+
}), f = r;
|
|
23
25
|
export {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
f as PieTextarea,
|
|
27
|
+
d as defaultProps,
|
|
28
|
+
g as resizeModes,
|
|
29
|
+
C as sizes,
|
|
30
|
+
h as statusTypes
|
|
28
31
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@justeattakeaway/pie-textarea",
|
|
3
3
|
"description": "PIE Design System Textarea built using Web Components",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"license": "Apache-2.0",
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@custom-elements-manifest/analyzer": "0.9.0",
|
|
39
|
-
"@justeattakeaway/pie-components-config": "0.
|
|
39
|
+
"@justeattakeaway/pie-components-config": "0.18.0",
|
|
40
40
|
"@justeattakeaway/pie-css": "0.12.1",
|
|
41
41
|
"@types/lodash.throttle": "4.1.9",
|
|
42
42
|
"cem-plugin-module-file-extensions": "0.0.5"
|
package/src/defs.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
|
2
2
|
|
|
3
3
|
export const sizes = ['small', 'medium', 'large'] as const;
|
|
4
4
|
export const resizeModes = ['auto', 'manual'] as const;
|
|
5
|
+
export const statusTypes = ['default', 'success', 'error'] as const;
|
|
5
6
|
|
|
6
7
|
export interface TextareaProps {
|
|
7
8
|
/**
|
|
@@ -31,6 +32,16 @@ export interface TextareaProps {
|
|
|
31
32
|
*/
|
|
32
33
|
defaultValue?: string;
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* An optional assistive text to display below the textarea element. Must be provided when the status is success or error.
|
|
37
|
+
*/
|
|
38
|
+
assistiveText?: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The status of the textarea component / assistive text. Can be default, success or error.
|
|
42
|
+
*/
|
|
43
|
+
status?: typeof statusTypes[number];
|
|
44
|
+
|
|
34
45
|
/**
|
|
35
46
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
36
47
|
*/
|
|
@@ -75,7 +86,7 @@ export interface TextareaProps {
|
|
|
75
86
|
/**
|
|
76
87
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
77
88
|
*/
|
|
78
|
-
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'defaultValue'>>;
|
|
89
|
+
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'assistiveText' | 'defaultValue'>>;
|
|
79
90
|
|
|
80
91
|
/**
|
|
81
92
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -86,6 +97,7 @@ export const defaultProps: DefaultProps = {
|
|
|
86
97
|
resize: 'auto',
|
|
87
98
|
label: '',
|
|
88
99
|
value: '',
|
|
100
|
+
status: 'default',
|
|
89
101
|
autoFocus: false,
|
|
90
102
|
readonly: false,
|
|
91
103
|
required: false,
|
package/src/index.ts
CHANGED
|
@@ -1,34 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
|
-
LitElement, html, unsafeCSS, PropertyValues, nothing,
|
|
2
|
+
LitElement, html, unsafeCSS, type PropertyValues, nothing,
|
|
3
3
|
} from 'lit';
|
|
4
|
-
|
|
5
4
|
import { property, query } from 'lit/decorators.js';
|
|
5
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
6
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
7
|
import { live } from 'lit/directives/live.js';
|
|
7
8
|
import throttle from 'lodash.throttle';
|
|
8
9
|
|
|
10
|
+
import '@justeattakeaway/pie-assistive-text';
|
|
11
|
+
import '@justeattakeaway/pie-form-label';
|
|
9
12
|
import {
|
|
10
|
-
validPropertyValues, RtlMixin, defineCustomElement, FormControlMixin, wrapNativeEvent,
|
|
13
|
+
validPropertyValues, RtlMixin, defineCustomElement, FormControlMixin, wrapNativeEvent, type PIEInputElement,
|
|
11
14
|
} from '@justeattakeaway/pie-webc-core';
|
|
12
15
|
|
|
13
|
-
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
14
16
|
import styles from './textarea.scss?inline';
|
|
15
17
|
import {
|
|
16
|
-
TextareaProps, defaultProps, sizes, resizeModes,
|
|
18
|
+
type TextareaProps, defaultProps, sizes, resizeModes, statusTypes,
|
|
17
19
|
} from './defs';
|
|
18
20
|
|
|
19
|
-
import '@justeattakeaway/pie-form-label';
|
|
20
|
-
|
|
21
21
|
// Valid values available to consumers
|
|
22
22
|
export * from './defs';
|
|
23
23
|
|
|
24
24
|
const componentSelector = 'pie-textarea';
|
|
25
|
+
const assistiveTextIdValue = 'assistive-text';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* @tagname pie-textarea
|
|
28
29
|
* @event {InputEvent} input - when the textarea value is changed.
|
|
29
30
|
* @event {CustomEvent} change - when the textarea value is changed.
|
|
30
31
|
*/
|
|
31
|
-
export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implements TextareaProps {
|
|
32
|
+
export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implements TextareaProps, PIEInputElement {
|
|
32
33
|
static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };
|
|
33
34
|
|
|
34
35
|
@property({ type: String })
|
|
@@ -64,18 +65,28 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
64
65
|
public required = defaultProps.required;
|
|
65
66
|
|
|
66
67
|
@property({ type: String })
|
|
67
|
-
|
|
68
|
+
@validPropertyValues(componentSelector, statusTypes, defaultProps.status)
|
|
69
|
+
public status = defaultProps.status;
|
|
70
|
+
|
|
71
|
+
@property({ type: String })
|
|
72
|
+
public assistiveText: TextareaProps['assistiveText'];
|
|
73
|
+
|
|
74
|
+
@property({ type: String })
|
|
75
|
+
public name: TextareaProps['name'];
|
|
68
76
|
|
|
69
77
|
@property({ type: String })
|
|
70
|
-
public autocomplete
|
|
78
|
+
public autocomplete: TextareaProps['autocomplete'];
|
|
71
79
|
|
|
72
80
|
@query('textarea')
|
|
73
81
|
private _textarea!: HTMLTextAreaElement;
|
|
74
82
|
|
|
83
|
+
@query('textarea')
|
|
84
|
+
public focusTarget!: HTMLElement;
|
|
85
|
+
|
|
75
86
|
private _throttledResize = throttle(() => {
|
|
76
87
|
if (this.resize === 'auto') {
|
|
77
88
|
this._textarea.style.height = 'auto';
|
|
78
|
-
this._textarea.style.height = `${this._textarea.scrollHeight
|
|
89
|
+
this._textarea.style.height = `${this._textarea.scrollHeight}px`;
|
|
79
90
|
}
|
|
80
91
|
}, 100);
|
|
81
92
|
|
|
@@ -111,6 +122,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
111
122
|
this.restrictInputLength();
|
|
112
123
|
this._internals.setFormValue(this.value);
|
|
113
124
|
|
|
125
|
+
window.addEventListener('resize', () => this.handleResize());
|
|
114
126
|
this._textarea.addEventListener('keydown', this.handleKeyDown);
|
|
115
127
|
}
|
|
116
128
|
|
|
@@ -169,6 +181,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
169
181
|
|
|
170
182
|
public disconnectedCallback (): void {
|
|
171
183
|
this._textarea.removeEventListener('keydown', this.handleKeyDown);
|
|
184
|
+
window.removeEventListener('resize', () => this.handleResize());
|
|
172
185
|
}
|
|
173
186
|
|
|
174
187
|
renderLabel (label: string, maxLength?: number) {
|
|
@@ -179,6 +192,21 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
179
192
|
: nothing;
|
|
180
193
|
}
|
|
181
194
|
|
|
195
|
+
renderAssistiveText () {
|
|
196
|
+
if (!this.assistiveText) {
|
|
197
|
+
return nothing;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return html`
|
|
201
|
+
<pie-assistive-text
|
|
202
|
+
id="${assistiveTextIdValue}"
|
|
203
|
+
variant=${ifDefined(this.status)}
|
|
204
|
+
data-test-id="pie-textarea-assistive-text">
|
|
205
|
+
${this.assistiveText}
|
|
206
|
+
</pie-assistive-text>
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
|
|
182
210
|
render () {
|
|
183
211
|
const {
|
|
184
212
|
disabled,
|
|
@@ -192,15 +220,23 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
192
220
|
required,
|
|
193
221
|
label,
|
|
194
222
|
maxLength,
|
|
223
|
+
status,
|
|
224
|
+
assistiveText,
|
|
195
225
|
} = this;
|
|
196
226
|
|
|
197
|
-
|
|
227
|
+
const classes = {
|
|
228
|
+
'c-textareaWrapper': true,
|
|
229
|
+
'c-textarea--disabled': disabled,
|
|
230
|
+
'c-textarea--error': status === 'error',
|
|
231
|
+
[`c-textarea--resize-${resize}`]: true,
|
|
232
|
+
[`c-textarea--${size}`]: true,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
return html`<div>
|
|
236
|
+
${this.renderLabel(label, maxLength)}
|
|
198
237
|
<div
|
|
199
|
-
class="
|
|
200
|
-
data-test-id="pie-textarea-wrapper"
|
|
201
|
-
data-pie-size="${size}"
|
|
202
|
-
data-pie-resize="${resize}">
|
|
203
|
-
${this.renderLabel(label, maxLength)}
|
|
238
|
+
class="${classMap(classes)}"
|
|
239
|
+
data-test-id="pie-textarea-wrapper">
|
|
204
240
|
<textarea
|
|
205
241
|
id="${componentSelector}"
|
|
206
242
|
data-test-id="${componentSelector}"
|
|
@@ -211,10 +247,15 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
211
247
|
?readonly=${readonly}
|
|
212
248
|
?required=${required}
|
|
213
249
|
?disabled=${disabled}
|
|
250
|
+
aria-describedby=${ifDefined(assistiveText ? assistiveTextIdValue : undefined)}
|
|
251
|
+
aria-invalid=${status === 'error' ? 'true' : 'false'}
|
|
252
|
+
aria-errormessage="${ifDefined(status === 'error' ? assistiveTextIdValue : undefined)}"
|
|
214
253
|
@input=${this.handleInput}
|
|
215
254
|
@change=${this.handleChange}
|
|
216
255
|
></textarea>
|
|
217
|
-
</div
|
|
256
|
+
</div>
|
|
257
|
+
${this.renderAssistiveText()}
|
|
258
|
+
</div>`;
|
|
218
259
|
}
|
|
219
260
|
|
|
220
261
|
// Renders a `CSSResult` generated from SCSS by Vite
|
package/src/textarea.scss
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
@use '@justeattakeaway/pie-css/scss' as p;
|
|
2
2
|
|
|
3
3
|
// Heights are being defined based on the line height of the text and the padding.
|
|
4
|
+
// Some of the padding is in the wrapper element to properly position the textarea resize handle.
|
|
4
5
|
// Changing the `size` property affects the padding and therefore the height of the textarea.
|
|
5
6
|
// Default height is two lines of text.
|
|
6
7
|
// Minimum height in manual resize mode is one line of text.
|
|
@@ -9,81 +10,95 @@
|
|
|
9
10
|
--textarea-line-height: #{p.line-height(--dt-font-body-l-line-height)};
|
|
10
11
|
--textarea-border-thickness: 1px;
|
|
11
12
|
--textarea-resize: none;
|
|
12
|
-
--textarea-padding-inline: var(--dt-spacing-
|
|
13
|
-
--textarea-padding-block: var(--dt-spacing-
|
|
13
|
+
--textarea-padding-inline: var(--dt-spacing-c);
|
|
14
|
+
--textarea-padding-block: var(--dt-spacing-b);
|
|
14
15
|
--textarea-background-color: var(--dt-color-container-default);
|
|
15
16
|
--textarea-border-color: var(--dt-color-interactive-form);
|
|
16
17
|
--textarea-content-color: var(--dt-color-content-default);
|
|
17
18
|
|
|
18
19
|
// Default height is two lines of text
|
|
19
|
-
--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2)
|
|
20
|
+
--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2));
|
|
20
21
|
|
|
21
|
-
line-height: 0;
|
|
22
|
+
line-height: 0;
|
|
23
|
+
padding: var(--dt-spacing-a);
|
|
24
|
+
border: var(--textarea-border-thickness) solid var(--textarea-border-color);
|
|
25
|
+
background-color: var(--textarea-background-color);
|
|
26
|
+
border-radius: var(--dt-radius-rounded-c);
|
|
27
|
+
inline-size: 100%;
|
|
22
28
|
|
|
23
29
|
textarea {
|
|
24
30
|
@include p.font-size(--dt-font-body-l-size);
|
|
25
31
|
line-height: var(--textarea-line-height);
|
|
26
32
|
font-family: var(--dt-font-body-l-family);
|
|
27
33
|
resize: var(--textarea-resize);
|
|
28
|
-
border:
|
|
34
|
+
border: none;
|
|
29
35
|
background-color: var(--textarea-background-color);
|
|
30
36
|
color: var(--textarea-content-color);
|
|
31
37
|
|
|
32
|
-
border-radius: var(--dt-radius-rounded-c);
|
|
33
38
|
block-size: var(--textarea-height);
|
|
34
39
|
max-block-size: var(--textarea-max-height);
|
|
35
40
|
min-block-size: var(--textarea-min-height);
|
|
41
|
+
inline-size: 100%;
|
|
36
42
|
|
|
37
43
|
padding-block-start: var(--textarea-padding-block);
|
|
38
44
|
padding-block-end: var(--textarea-padding-block);
|
|
39
45
|
padding-inline-start: var(--textarea-padding-inline);
|
|
40
46
|
padding-inline-end: var(--textarea-padding-inline);
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
--textarea-content-color: var(--dt-color-content-disabled);
|
|
48
|
+
&:focus {
|
|
49
|
+
box-shadow: none;
|
|
50
|
+
outline: none;
|
|
46
51
|
}
|
|
52
|
+
}
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
&.c-textarea--disabled {
|
|
55
|
+
--textarea-background-color: var(--dt-color-disabled-01);
|
|
56
|
+
--textarea-border-color: var(--dt-color-disabled-01);
|
|
57
|
+
--textarea-content-color: var(--dt-color-content-disabled);
|
|
58
|
+
}
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
60
|
+
@media (hover: hover) {
|
|
61
|
+
&:hover:not(.c-textarea--disabled) {
|
|
62
|
+
--textarea-background-color: hsl(var(--dt-color-container-default-h), var(--dt-color-container-default-s), calc(var(--dt-color-container-default-l) + calc(-1 * var(--dt-color-hover-01))));
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
&:focus-within {
|
|
67
|
+
@include p.focus;
|
|
61
68
|
}
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
--textarea-padding-block: var(--dt-spacing-
|
|
70
|
+
&.c-textarea--large {
|
|
71
|
+
--textarea-padding-block: var(--dt-spacing-c);
|
|
65
72
|
}
|
|
66
73
|
|
|
67
|
-
|
|
74
|
+
&.c-textarea--small {
|
|
75
|
+
--textarea-padding-block: var(--dt-spacing-a);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&.c-textarea--resize-manual {
|
|
68
79
|
--textarea-resize: vertical;
|
|
69
80
|
|
|
70
81
|
// Minimum is one line of text
|
|
71
|
-
--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2)
|
|
82
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2));
|
|
72
83
|
|
|
73
84
|
@media (pointer: coarse) {
|
|
74
85
|
// Fixed size for touch devices
|
|
75
|
-
--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2)
|
|
76
|
-
--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2)
|
|
77
|
-
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2)
|
|
86
|
+
--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
87
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
88
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
78
89
|
--textarea-resize: none;
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
92
|
|
|
82
|
-
|
|
93
|
+
&.c-textarea--resize-auto {
|
|
83
94
|
// Maximum is six lines of text
|
|
84
|
-
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2)
|
|
95
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
85
96
|
|
|
86
97
|
// Minimum is two lines of text
|
|
87
98
|
--textarea-min-height: var(--textarea-height);
|
|
88
99
|
}
|
|
100
|
+
|
|
101
|
+
&.c-textarea--error {
|
|
102
|
+
--textarea-border-color: var(--dt-color-support-error);
|
|
103
|
+
}
|
|
89
104
|
}
|