@justeattakeaway/pie-textarea 0.6.1 → 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 +75 -5
- package/dist/index.d.ts +24 -4
- package/dist/index.js +164 -126
- package/dist/react.d.ts +24 -4
- package/dist/react.js +11 -8
- package/package.json +2 -2
- package/src/defs.ts +18 -1
- package/src/index.ts +63 -19
- 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",
|
|
@@ -89,6 +105,15 @@
|
|
|
89
105
|
"privacy": "public",
|
|
90
106
|
"attribute": "value"
|
|
91
107
|
},
|
|
108
|
+
{
|
|
109
|
+
"kind": "field",
|
|
110
|
+
"name": "defaultValue",
|
|
111
|
+
"type": {
|
|
112
|
+
"text": "TextareaProps['defaultValue']"
|
|
113
|
+
},
|
|
114
|
+
"privacy": "public",
|
|
115
|
+
"attribute": "defaultValue"
|
|
116
|
+
},
|
|
92
117
|
{
|
|
93
118
|
"kind": "field",
|
|
94
119
|
"name": "disabled",
|
|
@@ -141,11 +166,26 @@
|
|
|
141
166
|
"privacy": "public",
|
|
142
167
|
"attribute": "required"
|
|
143
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
|
+
},
|
|
144
184
|
{
|
|
145
185
|
"kind": "field",
|
|
146
186
|
"name": "name",
|
|
147
187
|
"type": {
|
|
148
|
-
"text": "TextareaProps['name']
|
|
188
|
+
"text": "TextareaProps['name']"
|
|
149
189
|
},
|
|
150
190
|
"privacy": "public",
|
|
151
191
|
"attribute": "name"
|
|
@@ -154,7 +194,7 @@
|
|
|
154
194
|
"kind": "field",
|
|
155
195
|
"name": "autocomplete",
|
|
156
196
|
"type": {
|
|
157
|
-
"text": "TextareaProps['autocomplete']
|
|
197
|
+
"text": "TextareaProps['autocomplete']"
|
|
158
198
|
},
|
|
159
199
|
"privacy": "public",
|
|
160
200
|
"attribute": "autocomplete"
|
|
@@ -167,6 +207,14 @@
|
|
|
167
207
|
},
|
|
168
208
|
"privacy": "private"
|
|
169
209
|
},
|
|
210
|
+
{
|
|
211
|
+
"kind": "field",
|
|
212
|
+
"name": "focusTarget",
|
|
213
|
+
"type": {
|
|
214
|
+
"text": "HTMLElement"
|
|
215
|
+
},
|
|
216
|
+
"privacy": "public"
|
|
217
|
+
},
|
|
170
218
|
{
|
|
171
219
|
"kind": "field",
|
|
172
220
|
"name": "_throttledResize",
|
|
@@ -263,6 +311,10 @@
|
|
|
263
311
|
}
|
|
264
312
|
}
|
|
265
313
|
]
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"kind": "method",
|
|
317
|
+
"name": "renderAssistiveText"
|
|
266
318
|
}
|
|
267
319
|
],
|
|
268
320
|
"events": [
|
|
@@ -286,6 +338,13 @@
|
|
|
286
338
|
"name": "value",
|
|
287
339
|
"fieldName": "value"
|
|
288
340
|
},
|
|
341
|
+
{
|
|
342
|
+
"name": "defaultValue",
|
|
343
|
+
"type": {
|
|
344
|
+
"text": "TextareaProps['defaultValue']"
|
|
345
|
+
},
|
|
346
|
+
"fieldName": "defaultValue"
|
|
347
|
+
},
|
|
289
348
|
{
|
|
290
349
|
"name": "disabled",
|
|
291
350
|
"fieldName": "disabled"
|
|
@@ -321,17 +380,28 @@
|
|
|
321
380
|
"name": "required",
|
|
322
381
|
"fieldName": "required"
|
|
323
382
|
},
|
|
383
|
+
{
|
|
384
|
+
"name": "status",
|
|
385
|
+
"fieldName": "status"
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
"name": "assistiveText",
|
|
389
|
+
"type": {
|
|
390
|
+
"text": "TextareaProps['assistiveText']"
|
|
391
|
+
},
|
|
392
|
+
"fieldName": "assistiveText"
|
|
393
|
+
},
|
|
324
394
|
{
|
|
325
395
|
"name": "name",
|
|
326
396
|
"type": {
|
|
327
|
-
"text": "TextareaProps['name']
|
|
397
|
+
"text": "TextareaProps['name']"
|
|
328
398
|
},
|
|
329
399
|
"fieldName": "name"
|
|
330
400
|
},
|
|
331
401
|
{
|
|
332
402
|
"name": "autocomplete",
|
|
333
403
|
"type": {
|
|
334
|
-
"text": "TextareaProps['autocomplete']
|
|
404
|
+
"text": "TextareaProps['autocomplete']"
|
|
335
405
|
},
|
|
336
406
|
"fieldName": "autocomplete"
|
|
337
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'>>;
|
|
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,13 +24,14 @@ 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;
|
|
30
31
|
slotAssignment?: SlotAssignmentMode | undefined;
|
|
31
32
|
};
|
|
32
33
|
value: string;
|
|
34
|
+
defaultValue: TextareaProps['defaultValue'];
|
|
33
35
|
disabled: boolean;
|
|
34
36
|
size: "small" | "medium" | "large";
|
|
35
37
|
resize: "auto" | "manual";
|
|
@@ -38,9 +40,12 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
38
40
|
readonly: boolean;
|
|
39
41
|
autoFocus: boolean;
|
|
40
42
|
required: boolean;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
status: "default" | "error" | "success";
|
|
44
|
+
assistiveText: TextareaProps['assistiveText'];
|
|
45
|
+
name: TextareaProps['name'];
|
|
46
|
+
autocomplete: TextareaProps['autocomplete'];
|
|
43
47
|
private _textarea;
|
|
48
|
+
focusTarget: HTMLElement;
|
|
44
49
|
private _throttledResize;
|
|
45
50
|
/**
|
|
46
51
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -72,6 +77,7 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
72
77
|
private handleKeyDown;
|
|
73
78
|
disconnectedCallback(): void;
|
|
74
79
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
80
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
75
81
|
render(): TemplateResult<1>;
|
|
76
82
|
static styles: CSSResult;
|
|
77
83
|
}
|
|
@@ -82,6 +88,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
82
88
|
|
|
83
89
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
84
90
|
|
|
91
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
92
|
+
|
|
85
93
|
export declare interface TextareaProps {
|
|
86
94
|
/**
|
|
87
95
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -101,6 +109,18 @@ export declare interface TextareaProps {
|
|
|
101
109
|
* The value of the textarea (used as a key/value pair in HTML forms with `name`).
|
|
102
110
|
*/
|
|
103
111
|
value: string;
|
|
112
|
+
/**
|
|
113
|
+
* An optional default value to use when the textarea is reset.
|
|
114
|
+
*/
|
|
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];
|
|
104
124
|
/**
|
|
105
125
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
106
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,
|
|
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 = 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._throttledResize =
|
|
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 = c.value, this._internals.setFormValue(this.value);
|
|
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,81 +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 })
|
|
240
|
+
], o.prototype, "defaultValue", 2);
|
|
241
|
+
s([
|
|
242
|
+
l({ type: Boolean, reflect: !0 })
|
|
216
243
|
], o.prototype, "disabled", 2);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
244
|
+
s([
|
|
245
|
+
l({ type: String }),
|
|
246
|
+
O(m, me, c.size)
|
|
220
247
|
], o.prototype, "size", 2);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
248
|
+
s([
|
|
249
|
+
l({ type: String }),
|
|
250
|
+
O(m, be, c.resize)
|
|
224
251
|
], o.prototype, "resize", 2);
|
|
225
|
-
|
|
226
|
-
|
|
252
|
+
s([
|
|
253
|
+
l({ type: String })
|
|
227
254
|
], o.prototype, "label", 2);
|
|
228
|
-
|
|
229
|
-
|
|
255
|
+
s([
|
|
256
|
+
l({ type: Number })
|
|
230
257
|
], o.prototype, "maxLength", 2);
|
|
231
|
-
|
|
232
|
-
|
|
258
|
+
s([
|
|
259
|
+
l({ type: Boolean })
|
|
233
260
|
], o.prototype, "readonly", 2);
|
|
234
|
-
|
|
235
|
-
|
|
261
|
+
s([
|
|
262
|
+
l({ type: Boolean })
|
|
236
263
|
], o.prototype, "autoFocus", 2);
|
|
237
|
-
|
|
238
|
-
|
|
264
|
+
s([
|
|
265
|
+
l({ type: Boolean })
|
|
239
266
|
], o.prototype, "required", 2);
|
|
240
|
-
|
|
241
|
-
|
|
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 })
|
|
242
276
|
], o.prototype, "name", 2);
|
|
243
|
-
|
|
244
|
-
|
|
277
|
+
s([
|
|
278
|
+
l({ type: String })
|
|
245
279
|
], o.prototype, "autocomplete", 2);
|
|
246
|
-
|
|
247
|
-
|
|
280
|
+
s([
|
|
281
|
+
P("textarea")
|
|
248
282
|
], o.prototype, "_textarea", 2);
|
|
249
|
-
|
|
283
|
+
s([
|
|
284
|
+
P("textarea")
|
|
285
|
+
], o.prototype, "focusTarget", 2);
|
|
286
|
+
J(m, o);
|
|
250
287
|
export {
|
|
251
288
|
o as PieTextarea,
|
|
252
289
|
c as defaultProps,
|
|
253
|
-
|
|
254
|
-
|
|
290
|
+
be as resizeModes,
|
|
291
|
+
me as sizes,
|
|
292
|
+
ye as statusTypes
|
|
255
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'>>;
|
|
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,13 +27,14 @@ 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;
|
|
33
34
|
slotAssignment?: SlotAssignmentMode | undefined;
|
|
34
35
|
};
|
|
35
36
|
value: string;
|
|
37
|
+
defaultValue: TextareaProps['defaultValue'];
|
|
36
38
|
disabled: boolean;
|
|
37
39
|
size: "small" | "medium" | "large";
|
|
38
40
|
resize: "auto" | "manual";
|
|
@@ -41,9 +43,12 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
41
43
|
readonly: boolean;
|
|
42
44
|
autoFocus: boolean;
|
|
43
45
|
required: boolean;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
status: "default" | "error" | "success";
|
|
47
|
+
assistiveText: TextareaProps['assistiveText'];
|
|
48
|
+
name: TextareaProps['name'];
|
|
49
|
+
autocomplete: TextareaProps['autocomplete'];
|
|
46
50
|
private _textarea;
|
|
51
|
+
focusTarget: HTMLElement;
|
|
47
52
|
private _throttledResize;
|
|
48
53
|
/**
|
|
49
54
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -75,6 +80,7 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
75
80
|
private handleKeyDown;
|
|
76
81
|
disconnectedCallback(): void;
|
|
77
82
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
83
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
78
84
|
render(): TemplateResult<1>;
|
|
79
85
|
static styles: CSSResult;
|
|
80
86
|
}
|
|
@@ -92,6 +98,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
92
98
|
|
|
93
99
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
94
100
|
|
|
101
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
102
|
+
|
|
95
103
|
export declare interface TextareaProps {
|
|
96
104
|
/**
|
|
97
105
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -111,6 +119,18 @@ export declare interface TextareaProps {
|
|
|
111
119
|
* The value of the textarea (used as a key/value pair in HTML forms with `name`).
|
|
112
120
|
*/
|
|
113
121
|
value: string;
|
|
122
|
+
/**
|
|
123
|
+
* An optional default value to use when the textarea is reset.
|
|
124
|
+
*/
|
|
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];
|
|
114
134
|
/**
|
|
115
135
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
116
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
|
/**
|
|
@@ -26,6 +27,21 @@ export interface TextareaProps {
|
|
|
26
27
|
*/
|
|
27
28
|
value: string;
|
|
28
29
|
|
|
30
|
+
/**
|
|
31
|
+
* An optional default value to use when the textarea is reset.
|
|
32
|
+
*/
|
|
33
|
+
defaultValue?: string;
|
|
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
|
+
|
|
29
45
|
/**
|
|
30
46
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
31
47
|
*/
|
|
@@ -70,7 +86,7 @@ export interface TextareaProps {
|
|
|
70
86
|
/**
|
|
71
87
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
72
88
|
*/
|
|
73
|
-
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength'>>;
|
|
89
|
+
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'assistiveText' | 'defaultValue'>>;
|
|
74
90
|
|
|
75
91
|
/**
|
|
76
92
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -81,6 +97,7 @@ export const defaultProps: DefaultProps = {
|
|
|
81
97
|
resize: 'auto',
|
|
82
98
|
label: '',
|
|
83
99
|
value: '',
|
|
100
|
+
status: 'default',
|
|
84
101
|
autoFocus: false,
|
|
85
102
|
readonly: false,
|
|
86
103
|
required: false,
|
package/src/index.ts
CHANGED
|
@@ -1,39 +1,43 @@
|
|
|
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 })
|
|
35
36
|
public value = defaultProps.value;
|
|
36
37
|
|
|
38
|
+
@property({ type: String })
|
|
39
|
+
public defaultValue: TextareaProps['defaultValue'];
|
|
40
|
+
|
|
37
41
|
@property({ type: Boolean, reflect: true })
|
|
38
42
|
public disabled = defaultProps.disabled;
|
|
39
43
|
|
|
@@ -61,18 +65,28 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
61
65
|
public required = defaultProps.required;
|
|
62
66
|
|
|
63
67
|
@property({ type: String })
|
|
64
|
-
|
|
68
|
+
@validPropertyValues(componentSelector, statusTypes, defaultProps.status)
|
|
69
|
+
public status = defaultProps.status;
|
|
65
70
|
|
|
66
71
|
@property({ type: String })
|
|
67
|
-
public
|
|
72
|
+
public assistiveText: TextareaProps['assistiveText'];
|
|
73
|
+
|
|
74
|
+
@property({ type: String })
|
|
75
|
+
public name: TextareaProps['name'];
|
|
76
|
+
|
|
77
|
+
@property({ type: String })
|
|
78
|
+
public autocomplete: TextareaProps['autocomplete'];
|
|
68
79
|
|
|
69
80
|
@query('textarea')
|
|
70
81
|
private _textarea!: HTMLTextAreaElement;
|
|
71
82
|
|
|
83
|
+
@query('textarea')
|
|
84
|
+
public focusTarget!: HTMLElement;
|
|
85
|
+
|
|
72
86
|
private _throttledResize = throttle(() => {
|
|
73
87
|
if (this.resize === 'auto') {
|
|
74
88
|
this._textarea.style.height = 'auto';
|
|
75
|
-
this._textarea.style.height = `${this._textarea.scrollHeight
|
|
89
|
+
this._textarea.style.height = `${this._textarea.scrollHeight}px`;
|
|
76
90
|
}
|
|
77
91
|
}, 100);
|
|
78
92
|
|
|
@@ -99,7 +113,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
99
113
|
* Resets the value to the default value.
|
|
100
114
|
*/
|
|
101
115
|
public formResetCallback (): void {
|
|
102
|
-
this.value = defaultProps.value;
|
|
116
|
+
this.value = this.defaultValue ?? defaultProps.value;
|
|
103
117
|
|
|
104
118
|
this._internals.setFormValue(this.value);
|
|
105
119
|
}
|
|
@@ -108,6 +122,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
108
122
|
this.restrictInputLength();
|
|
109
123
|
this._internals.setFormValue(this.value);
|
|
110
124
|
|
|
125
|
+
window.addEventListener('resize', () => this.handleResize());
|
|
111
126
|
this._textarea.addEventListener('keydown', this.handleKeyDown);
|
|
112
127
|
}
|
|
113
128
|
|
|
@@ -166,6 +181,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
166
181
|
|
|
167
182
|
public disconnectedCallback (): void {
|
|
168
183
|
this._textarea.removeEventListener('keydown', this.handleKeyDown);
|
|
184
|
+
window.removeEventListener('resize', () => this.handleResize());
|
|
169
185
|
}
|
|
170
186
|
|
|
171
187
|
renderLabel (label: string, maxLength?: number) {
|
|
@@ -176,6 +192,21 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
176
192
|
: nothing;
|
|
177
193
|
}
|
|
178
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
|
+
|
|
179
210
|
render () {
|
|
180
211
|
const {
|
|
181
212
|
disabled,
|
|
@@ -189,15 +220,23 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
189
220
|
required,
|
|
190
221
|
label,
|
|
191
222
|
maxLength,
|
|
223
|
+
status,
|
|
224
|
+
assistiveText,
|
|
192
225
|
} = this;
|
|
193
226
|
|
|
194
|
-
|
|
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)}
|
|
195
237
|
<div
|
|
196
|
-
class="
|
|
197
|
-
data-test-id="pie-textarea-wrapper"
|
|
198
|
-
data-pie-size="${size}"
|
|
199
|
-
data-pie-resize="${resize}">
|
|
200
|
-
${this.renderLabel(label, maxLength)}
|
|
238
|
+
class="${classMap(classes)}"
|
|
239
|
+
data-test-id="pie-textarea-wrapper">
|
|
201
240
|
<textarea
|
|
202
241
|
id="${componentSelector}"
|
|
203
242
|
data-test-id="${componentSelector}"
|
|
@@ -208,10 +247,15 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
208
247
|
?readonly=${readonly}
|
|
209
248
|
?required=${required}
|
|
210
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)}"
|
|
211
253
|
@input=${this.handleInput}
|
|
212
254
|
@change=${this.handleChange}
|
|
213
255
|
></textarea>
|
|
214
|
-
</div
|
|
256
|
+
</div>
|
|
257
|
+
${this.renderAssistiveText()}
|
|
258
|
+
</div>`;
|
|
215
259
|
}
|
|
216
260
|
|
|
217
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
|
}
|