@justeattakeaway/pie-textarea 0.7.0 → 0.9.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 +192 -150
- package/dist/react.d.ts +24 -4
- package/dist/react.js +11 -8
- package/package.json +2 -2
- package/src/defs.ts +19 -1
- package/src/index.ts +65 -18
- package/src/textarea.scss +55 -27
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 placeholder: '',\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,11 +194,20 @@
|
|
|
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"
|
|
170
201
|
},
|
|
202
|
+
{
|
|
203
|
+
"kind": "field",
|
|
204
|
+
"name": "placeholder",
|
|
205
|
+
"type": {
|
|
206
|
+
"text": "TextareaProps['placeholder']"
|
|
207
|
+
},
|
|
208
|
+
"privacy": "public",
|
|
209
|
+
"attribute": "placeholder"
|
|
210
|
+
},
|
|
171
211
|
{
|
|
172
212
|
"kind": "field",
|
|
173
213
|
"name": "_textarea",
|
|
@@ -176,6 +216,14 @@
|
|
|
176
216
|
},
|
|
177
217
|
"privacy": "private"
|
|
178
218
|
},
|
|
219
|
+
{
|
|
220
|
+
"kind": "field",
|
|
221
|
+
"name": "focusTarget",
|
|
222
|
+
"type": {
|
|
223
|
+
"text": "HTMLElement"
|
|
224
|
+
},
|
|
225
|
+
"privacy": "public"
|
|
226
|
+
},
|
|
179
227
|
{
|
|
180
228
|
"kind": "field",
|
|
181
229
|
"name": "_throttledResize",
|
|
@@ -272,6 +320,10 @@
|
|
|
272
320
|
}
|
|
273
321
|
}
|
|
274
322
|
]
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
"kind": "method",
|
|
326
|
+
"name": "renderAssistiveText"
|
|
275
327
|
}
|
|
276
328
|
],
|
|
277
329
|
"events": [
|
|
@@ -337,19 +389,37 @@
|
|
|
337
389
|
"name": "required",
|
|
338
390
|
"fieldName": "required"
|
|
339
391
|
},
|
|
392
|
+
{
|
|
393
|
+
"name": "status",
|
|
394
|
+
"fieldName": "status"
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
"name": "assistiveText",
|
|
398
|
+
"type": {
|
|
399
|
+
"text": "TextareaProps['assistiveText']"
|
|
400
|
+
},
|
|
401
|
+
"fieldName": "assistiveText"
|
|
402
|
+
},
|
|
340
403
|
{
|
|
341
404
|
"name": "name",
|
|
342
405
|
"type": {
|
|
343
|
-
"text": "TextareaProps['name']
|
|
406
|
+
"text": "TextareaProps['name']"
|
|
344
407
|
},
|
|
345
408
|
"fieldName": "name"
|
|
346
409
|
},
|
|
347
410
|
{
|
|
348
411
|
"name": "autocomplete",
|
|
349
412
|
"type": {
|
|
350
|
-
"text": "TextareaProps['autocomplete']
|
|
413
|
+
"text": "TextareaProps['autocomplete']"
|
|
351
414
|
},
|
|
352
415
|
"fieldName": "autocomplete"
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"name": "placeholder",
|
|
419
|
+
"type": {
|
|
420
|
+
"text": "TextareaProps['placeholder']"
|
|
421
|
+
},
|
|
422
|
+
"fieldName": "placeholder"
|
|
353
423
|
}
|
|
354
424
|
],
|
|
355
425
|
"mixins": [
|
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,13 @@ 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'];
|
|
47
|
+
placeholder: TextareaProps['placeholder'];
|
|
44
48
|
private _textarea;
|
|
49
|
+
focusTarget: HTMLElement;
|
|
45
50
|
private _throttledResize;
|
|
46
51
|
/**
|
|
47
52
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -73,6 +78,7 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
73
78
|
private handleKeyDown;
|
|
74
79
|
disconnectedCallback(): void;
|
|
75
80
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
81
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
76
82
|
render(): TemplateResult<1>;
|
|
77
83
|
static styles: CSSResult;
|
|
78
84
|
}
|
|
@@ -83,6 +89,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
83
89
|
|
|
84
90
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
85
91
|
|
|
92
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
93
|
+
|
|
86
94
|
export declare interface TextareaProps {
|
|
87
95
|
/**
|
|
88
96
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -106,6 +114,14 @@ export declare interface TextareaProps {
|
|
|
106
114
|
* An optional default value to use when the textarea is reset.
|
|
107
115
|
*/
|
|
108
116
|
defaultValue?: string;
|
|
117
|
+
/**
|
|
118
|
+
* An optional assistive text to display below the textarea element. Must be provided when the status is success or error.
|
|
119
|
+
*/
|
|
120
|
+
assistiveText?: string;
|
|
121
|
+
/**
|
|
122
|
+
* The status of the textarea component / assistive text. Can be default, success or error.
|
|
123
|
+
*/
|
|
124
|
+
status?: typeof statusTypes[number];
|
|
109
125
|
/**
|
|
110
126
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
111
127
|
*/
|
|
@@ -139,6 +155,10 @@ export declare interface TextareaProps {
|
|
|
139
155
|
* If the `label` property is not set, this property will have no effect.
|
|
140
156
|
*/
|
|
141
157
|
maxLength?: number;
|
|
158
|
+
/**
|
|
159
|
+
* The placeholder text to display when the textarea is empty.
|
|
160
|
+
*/
|
|
161
|
+
placeholder?: string;
|
|
142
162
|
}
|
|
143
163
|
|
|
144
164
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,124 +1,128 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
1
|
+
import { LitElement as P, html as W, nothing as R, unsafeCSS as A } from "lit";
|
|
2
|
+
import { property as l, query as V } 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 q = "Expected a function", D = 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, oe = typeof self == "object" && self && self.Object === Object && self, ne = ie || oe || Function("return this")(), se = Object.prototype, le = se.toString, de = Math.max, ce = Math.min, j = function() {
|
|
14
|
+
return ne.Date.now();
|
|
13
15
|
};
|
|
14
|
-
function
|
|
15
|
-
var
|
|
16
|
+
function ue(t, e, a) {
|
|
17
|
+
var i, o, p, u, d, h, f = 0, k = !1, v = !1, y = !0;
|
|
16
18
|
if (typeof t != "function")
|
|
17
|
-
throw new TypeError(
|
|
18
|
-
e =
|
|
19
|
-
function
|
|
20
|
-
var
|
|
21
|
-
return
|
|
19
|
+
throw new TypeError(q);
|
|
20
|
+
e = M(e) || 0, _(a) && (k = !!a.leading, v = "maxWait" in a, p = v ? de(M(a.maxWait) || 0, e) : p, y = "trailing" in a ? !!a.trailing : y);
|
|
21
|
+
function g(n) {
|
|
22
|
+
var x = i, z = o;
|
|
23
|
+
return i = o = void 0, f = n, u = t.apply(z, x), u;
|
|
22
24
|
}
|
|
23
|
-
function
|
|
24
|
-
return
|
|
25
|
+
function S(n) {
|
|
26
|
+
return f = n, d = setTimeout($, e), k ? g(n) : u;
|
|
25
27
|
}
|
|
26
|
-
function
|
|
27
|
-
var
|
|
28
|
-
return v ?
|
|
28
|
+
function w(n) {
|
|
29
|
+
var x = n - h, z = n - f, F = e - x;
|
|
30
|
+
return v ? ce(F, p - z) : F;
|
|
29
31
|
}
|
|
30
|
-
function
|
|
31
|
-
var
|
|
32
|
-
return
|
|
32
|
+
function I(n) {
|
|
33
|
+
var x = n - h, z = n - f;
|
|
34
|
+
return h === void 0 || x >= e || x < 0 || v && z >= p;
|
|
33
35
|
}
|
|
34
|
-
function
|
|
35
|
-
var n =
|
|
36
|
-
if (
|
|
37
|
-
return
|
|
38
|
-
|
|
36
|
+
function $() {
|
|
37
|
+
var n = j();
|
|
38
|
+
if (I(n))
|
|
39
|
+
return C(n);
|
|
40
|
+
d = setTimeout($, w(n));
|
|
39
41
|
}
|
|
40
|
-
function
|
|
41
|
-
return
|
|
42
|
+
function C(n) {
|
|
43
|
+
return d = void 0, y && i ? g(n) : (i = o = void 0, u);
|
|
42
44
|
}
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
+
function B() {
|
|
46
|
+
d !== void 0 && clearTimeout(d), f = 0, i = h = o = d = void 0;
|
|
45
47
|
}
|
|
46
|
-
function
|
|
47
|
-
return
|
|
48
|
+
function N() {
|
|
49
|
+
return d === void 0 ? u : C(j());
|
|
48
50
|
}
|
|
49
|
-
function
|
|
50
|
-
var n =
|
|
51
|
-
if (
|
|
52
|
-
if (
|
|
53
|
-
return
|
|
51
|
+
function L() {
|
|
52
|
+
var n = j(), x = I(n);
|
|
53
|
+
if (i = arguments, o = this, h = n, x) {
|
|
54
|
+
if (d === void 0)
|
|
55
|
+
return S(h);
|
|
54
56
|
if (v)
|
|
55
|
-
return
|
|
57
|
+
return d = setTimeout($, e), g(h);
|
|
56
58
|
}
|
|
57
|
-
return
|
|
59
|
+
return d === void 0 && (d = setTimeout($, e)), u;
|
|
58
60
|
}
|
|
59
|
-
return
|
|
61
|
+
return L.cancel = B, L.flush = N, L;
|
|
60
62
|
}
|
|
61
|
-
function
|
|
62
|
-
var
|
|
63
|
+
function pe(t, e, a) {
|
|
64
|
+
var i = !0, o = !0;
|
|
63
65
|
if (typeof t != "function")
|
|
64
|
-
throw new TypeError(
|
|
65
|
-
return
|
|
66
|
-
leading:
|
|
66
|
+
throw new TypeError(q);
|
|
67
|
+
return _(a) && (i = "leading" in a ? !!a.leading : i, o = "trailing" in a ? !!a.trailing : o), ue(t, e, {
|
|
68
|
+
leading: i,
|
|
67
69
|
maxWait: e,
|
|
68
|
-
trailing:
|
|
70
|
+
trailing: o
|
|
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
77
|
function he(t) {
|
|
76
78
|
return !!t && typeof t == "object";
|
|
77
79
|
}
|
|
78
|
-
function
|
|
79
|
-
return typeof t == "symbol" || he(t) &&
|
|
80
|
+
function xe(t) {
|
|
81
|
+
return typeof t == "symbol" || he(t) && le.call(t) == Y;
|
|
80
82
|
}
|
|
81
|
-
function
|
|
83
|
+
function M(t) {
|
|
82
84
|
if (typeof t == "number")
|
|
83
85
|
return t;
|
|
84
|
-
if (
|
|
85
|
-
return
|
|
86
|
-
if (
|
|
86
|
+
if (xe(t))
|
|
87
|
+
return D;
|
|
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) ? D : +t;
|
|
95
97
|
}
|
|
96
|
-
var
|
|
97
|
-
const
|
|
98
|
-
`,
|
|
98
|
+
var fe = pe;
|
|
99
|
+
const ve = /* @__PURE__ */ Q(fe), 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-placeholder-color: var(--dt-color-content-subdued);--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 textarea::placeholder{color:var(--textarea-placeholder-color);opacity:1}.c-textareaWrapper.c-textarea--readonly{--textarea-background-color: var(--dt-color-container-subtle);--textarea-border-color: var(--dt-color-interactive-form)}.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);--textarea-placeholder-color: var(--dt-color-content-disabled)}@media (hover: hover){.c-textareaWrapper:hover:not(.c-textarea--disabled,.c-textarea--readonly){--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
|
+
`, be = ["small", "medium", "large"], me = ["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
|
+
placeholder: "",
|
|
107
|
+
status: "default",
|
|
104
108
|
autoFocus: !1,
|
|
105
109
|
readonly: !1,
|
|
106
110
|
required: !1
|
|
107
111
|
};
|
|
108
|
-
var
|
|
109
|
-
for (var
|
|
110
|
-
(
|
|
111
|
-
return
|
|
112
|
+
var ze = Object.defineProperty, ke = Object.getOwnPropertyDescriptor, s = (t, e, a, i) => {
|
|
113
|
+
for (var o = i > 1 ? void 0 : i ? ke(e, a) : e, p = t.length - 1, u; p >= 0; p--)
|
|
114
|
+
(u = t[p]) && (o = (i ? u(e, a, o) : u(o)) || o);
|
|
115
|
+
return i && o && ze(e, a, o), o;
|
|
112
116
|
};
|
|
113
|
-
const
|
|
114
|
-
class
|
|
117
|
+
const m = "pie-textarea", E = "assistive-text";
|
|
118
|
+
class r extends H(U(P)) {
|
|
115
119
|
constructor() {
|
|
116
|
-
super(...arguments), this.value =
|
|
117
|
-
this.resize === "auto" && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight
|
|
120
|
+
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(() => {
|
|
121
|
+
this.resize === "auto" && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight}px`);
|
|
118
122
|
}, 100), this.handleInput = (e) => {
|
|
119
123
|
this.value = e.target.value, this.restrictInputLength(), this._internals.setFormValue(this.value), this.handleResize();
|
|
120
124
|
}, this.handleChange = (e) => {
|
|
121
|
-
const a =
|
|
125
|
+
const a = X(e);
|
|
122
126
|
this.dispatchEvent(a);
|
|
123
127
|
}, this.handleKeyDown = (e) => {
|
|
124
128
|
e.key === "Enter" && e.stopPropagation();
|
|
@@ -145,10 +149,10 @@ class o extends K(G(w)) {
|
|
|
145
149
|
* Resets the value to the default value.
|
|
146
150
|
*/
|
|
147
151
|
formResetCallback() {
|
|
148
|
-
this.value = this.defaultValue ??
|
|
152
|
+
this.value = this.defaultValue ?? c.value, this._internals.setFormValue(this.value);
|
|
149
153
|
}
|
|
150
154
|
firstUpdated() {
|
|
151
|
-
this.restrictInputLength(), this._internals.setFormValue(this.value), this._textarea.addEventListener("keydown", this.handleKeyDown);
|
|
155
|
+
this.restrictInputLength(), this._internals.setFormValue(this.value), window.addEventListener("resize", () => this.handleResize()), this._textarea.addEventListener("keydown", this.handleKeyDown);
|
|
152
156
|
}
|
|
153
157
|
handleResize() {
|
|
154
158
|
this._throttledResize();
|
|
@@ -163,96 +167,134 @@ class o extends K(G(w)) {
|
|
|
163
167
|
e.has("value") && (this.restrictInputLength(), this._internals.setFormValue(this.value)), this.resize === "auto" && (e.has("resize") || e.has("size")) && this.handleResize();
|
|
164
168
|
}
|
|
165
169
|
disconnectedCallback() {
|
|
166
|
-
this._textarea.removeEventListener("keydown", this.handleKeyDown);
|
|
170
|
+
this._textarea.removeEventListener("keydown", this.handleKeyDown), window.removeEventListener("resize", () => this.handleResize());
|
|
167
171
|
}
|
|
168
172
|
renderLabel(e, a) {
|
|
169
|
-
const
|
|
170
|
-
return e != null && e.length ?
|
|
173
|
+
const i = a ? `${this.value.length}/${a}` : void 0;
|
|
174
|
+
return e != null && e.length ? W`<pie-form-label for="${m}" trailing=${b(i)}>${e}</pie-form-label>` : R;
|
|
175
|
+
}
|
|
176
|
+
renderAssistiveText() {
|
|
177
|
+
return this.assistiveText ? W`
|
|
178
|
+
<pie-assistive-text
|
|
179
|
+
id="${E}"
|
|
180
|
+
variant=${b(this.status)}
|
|
181
|
+
data-test-id="pie-textarea-assistive-text">
|
|
182
|
+
${this.assistiveText}
|
|
183
|
+
</pie-assistive-text>
|
|
184
|
+
` : R;
|
|
171
185
|
}
|
|
172
186
|
render() {
|
|
173
187
|
const {
|
|
174
188
|
disabled: e,
|
|
175
189
|
resize: a,
|
|
176
|
-
size:
|
|
177
|
-
autocomplete:
|
|
178
|
-
autoFocus:
|
|
179
|
-
name:
|
|
180
|
-
readonly:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
190
|
+
size: i,
|
|
191
|
+
autocomplete: o,
|
|
192
|
+
autoFocus: p,
|
|
193
|
+
name: u,
|
|
194
|
+
readonly: d,
|
|
195
|
+
placeholder: h,
|
|
196
|
+
value: f,
|
|
197
|
+
required: k,
|
|
198
|
+
label: v,
|
|
199
|
+
maxLength: y,
|
|
200
|
+
status: g,
|
|
201
|
+
assistiveText: S
|
|
202
|
+
} = this, w = {
|
|
203
|
+
"c-textareaWrapper": !0,
|
|
204
|
+
"c-textarea--disabled": e,
|
|
205
|
+
"c-textarea--readonly": d,
|
|
206
|
+
"c-textarea--error": g === "error",
|
|
207
|
+
[`c-textarea--resize-${a}`]: !0,
|
|
208
|
+
[`c-textarea--${i}`]: !0
|
|
209
|
+
};
|
|
210
|
+
return W`<div>
|
|
211
|
+
${this.renderLabel(v, y)}
|
|
187
212
|
<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)}
|
|
213
|
+
class="${K(w)}"
|
|
214
|
+
data-test-id="pie-textarea-wrapper">
|
|
193
215
|
<textarea
|
|
194
|
-
id="${
|
|
195
|
-
data-test-id="${
|
|
196
|
-
name=${
|
|
197
|
-
autocomplete=${
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
?
|
|
201
|
-
?
|
|
216
|
+
id="${m}"
|
|
217
|
+
data-test-id="${m}"
|
|
218
|
+
name=${b(u)}
|
|
219
|
+
autocomplete=${b(o)}
|
|
220
|
+
placeholder=${b(h)}
|
|
221
|
+
.value=${G(f)}
|
|
222
|
+
?autofocus=${p}
|
|
223
|
+
?readonly=${d}
|
|
224
|
+
?required=${k}
|
|
202
225
|
?disabled=${e}
|
|
226
|
+
aria-describedby=${b(S ? E : void 0)}
|
|
227
|
+
aria-invalid=${g === "error" ? "true" : "false"}
|
|
228
|
+
aria-errormessage="${b(g === "error" ? E : void 0)}"
|
|
203
229
|
@input=${this.handleInput}
|
|
204
230
|
@change=${this.handleChange}
|
|
205
231
|
></textarea>
|
|
206
|
-
</div
|
|
232
|
+
</div>
|
|
233
|
+
${this.renderAssistiveText()}
|
|
234
|
+
</div>`;
|
|
207
235
|
}
|
|
208
236
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
],
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
],
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
],
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
],
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
],
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
],
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
],
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
],
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
],
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
],
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
237
|
+
r.shadowRootOptions = { ...P.shadowRootOptions, delegatesFocus: !0 };
|
|
238
|
+
r.styles = A(ge);
|
|
239
|
+
s([
|
|
240
|
+
l({ type: String })
|
|
241
|
+
], r.prototype, "value", 2);
|
|
242
|
+
s([
|
|
243
|
+
l({ type: String })
|
|
244
|
+
], r.prototype, "defaultValue", 2);
|
|
245
|
+
s([
|
|
246
|
+
l({ type: Boolean, reflect: !0 })
|
|
247
|
+
], r.prototype, "disabled", 2);
|
|
248
|
+
s([
|
|
249
|
+
l({ type: String }),
|
|
250
|
+
O(m, be, c.size)
|
|
251
|
+
], r.prototype, "size", 2);
|
|
252
|
+
s([
|
|
253
|
+
l({ type: String }),
|
|
254
|
+
O(m, me, c.resize)
|
|
255
|
+
], r.prototype, "resize", 2);
|
|
256
|
+
s([
|
|
257
|
+
l({ type: String })
|
|
258
|
+
], r.prototype, "label", 2);
|
|
259
|
+
s([
|
|
260
|
+
l({ type: Number })
|
|
261
|
+
], r.prototype, "maxLength", 2);
|
|
262
|
+
s([
|
|
263
|
+
l({ type: Boolean })
|
|
264
|
+
], r.prototype, "readonly", 2);
|
|
265
|
+
s([
|
|
266
|
+
l({ type: Boolean })
|
|
267
|
+
], r.prototype, "autoFocus", 2);
|
|
268
|
+
s([
|
|
269
|
+
l({ type: Boolean })
|
|
270
|
+
], r.prototype, "required", 2);
|
|
271
|
+
s([
|
|
272
|
+
l({ type: String }),
|
|
273
|
+
O(m, ye, c.status)
|
|
274
|
+
], r.prototype, "status", 2);
|
|
275
|
+
s([
|
|
276
|
+
l({ type: String })
|
|
277
|
+
], r.prototype, "assistiveText", 2);
|
|
278
|
+
s([
|
|
279
|
+
l({ type: String })
|
|
280
|
+
], r.prototype, "name", 2);
|
|
281
|
+
s([
|
|
282
|
+
l({ type: String })
|
|
283
|
+
], r.prototype, "autocomplete", 2);
|
|
284
|
+
s([
|
|
285
|
+
l({ type: String })
|
|
286
|
+
], r.prototype, "placeholder", 2);
|
|
287
|
+
s([
|
|
288
|
+
V("textarea")
|
|
289
|
+
], r.prototype, "_textarea", 2);
|
|
290
|
+
s([
|
|
291
|
+
V("textarea")
|
|
292
|
+
], r.prototype, "focusTarget", 2);
|
|
293
|
+
J(m, r);
|
|
253
294
|
export {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
295
|
+
r as PieTextarea,
|
|
296
|
+
c as defaultProps,
|
|
297
|
+
me as resizeModes,
|
|
298
|
+
be as sizes,
|
|
299
|
+
ye as statusTypes
|
|
258
300
|
};
|
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,13 @@ 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'];
|
|
50
|
+
placeholder: TextareaProps['placeholder'];
|
|
47
51
|
private _textarea;
|
|
52
|
+
focusTarget: HTMLElement;
|
|
48
53
|
private _throttledResize;
|
|
49
54
|
/**
|
|
50
55
|
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
@@ -76,6 +81,7 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
76
81
|
private handleKeyDown;
|
|
77
82
|
disconnectedCallback(): void;
|
|
78
83
|
renderLabel(label: string, maxLength?: number): TemplateResult<1> | typeof nothing;
|
|
84
|
+
renderAssistiveText(): TemplateResult<1> | typeof nothing;
|
|
79
85
|
render(): TemplateResult<1>;
|
|
80
86
|
static styles: CSSResult;
|
|
81
87
|
}
|
|
@@ -93,6 +99,8 @@ export declare const resizeModes: readonly ["auto", "manual"];
|
|
|
93
99
|
|
|
94
100
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
95
101
|
|
|
102
|
+
export declare const statusTypes: readonly ["default", "success", "error"];
|
|
103
|
+
|
|
96
104
|
export declare interface TextareaProps {
|
|
97
105
|
/**
|
|
98
106
|
* Same as the HTML disabled attribute - indicates whether the textarea is disabled.
|
|
@@ -116,6 +124,14 @@ export declare interface TextareaProps {
|
|
|
116
124
|
* An optional default value to use when the textarea is reset.
|
|
117
125
|
*/
|
|
118
126
|
defaultValue?: string;
|
|
127
|
+
/**
|
|
128
|
+
* An optional assistive text to display below the textarea element. Must be provided when the status is success or error.
|
|
129
|
+
*/
|
|
130
|
+
assistiveText?: string;
|
|
131
|
+
/**
|
|
132
|
+
* The status of the textarea component / assistive text. Can be default, success or error.
|
|
133
|
+
*/
|
|
134
|
+
status?: typeof statusTypes[number];
|
|
119
135
|
/**
|
|
120
136
|
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
121
137
|
*/
|
|
@@ -149,6 +165,10 @@ export declare interface TextareaProps {
|
|
|
149
165
|
* If the `label` property is not set, this property will have no effect.
|
|
150
166
|
*/
|
|
151
167
|
maxLength?: number;
|
|
168
|
+
/**
|
|
169
|
+
* The placeholder text to display when the textarea is empty.
|
|
170
|
+
*/
|
|
171
|
+
placeholder?: string;
|
|
152
172
|
}
|
|
153
173
|
|
|
154
174
|
export { }
|
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.9.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
|
*/
|
|
@@ -70,12 +81,17 @@ export interface TextareaProps {
|
|
|
70
81
|
* If the `label` property is not set, this property will have no effect.
|
|
71
82
|
*/
|
|
72
83
|
maxLength?: number;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The placeholder text to display when the textarea is empty.
|
|
87
|
+
*/
|
|
88
|
+
placeholder?: string;
|
|
73
89
|
}
|
|
74
90
|
|
|
75
91
|
/**
|
|
76
92
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
77
93
|
*/
|
|
78
|
-
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'defaultValue'>>;
|
|
94
|
+
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete' | 'maxLength' | 'assistiveText' | 'defaultValue'>>;
|
|
79
95
|
|
|
80
96
|
/**
|
|
81
97
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -86,6 +102,8 @@ export const defaultProps: DefaultProps = {
|
|
|
86
102
|
resize: 'auto',
|
|
87
103
|
label: '',
|
|
88
104
|
value: '',
|
|
105
|
+
placeholder: '',
|
|
106
|
+
status: 'default',
|
|
89
107
|
autoFocus: false,
|
|
90
108
|
readonly: false,
|
|
91
109
|
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,31 @@ 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'];
|
|
79
|
+
|
|
80
|
+
@property({ type: String })
|
|
81
|
+
public placeholder: TextareaProps['placeholder'];
|
|
71
82
|
|
|
72
83
|
@query('textarea')
|
|
73
84
|
private _textarea!: HTMLTextAreaElement;
|
|
74
85
|
|
|
86
|
+
@query('textarea')
|
|
87
|
+
public focusTarget!: HTMLElement;
|
|
88
|
+
|
|
75
89
|
private _throttledResize = throttle(() => {
|
|
76
90
|
if (this.resize === 'auto') {
|
|
77
91
|
this._textarea.style.height = 'auto';
|
|
78
|
-
this._textarea.style.height = `${this._textarea.scrollHeight
|
|
92
|
+
this._textarea.style.height = `${this._textarea.scrollHeight}px`;
|
|
79
93
|
}
|
|
80
94
|
}, 100);
|
|
81
95
|
|
|
@@ -111,6 +125,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
111
125
|
this.restrictInputLength();
|
|
112
126
|
this._internals.setFormValue(this.value);
|
|
113
127
|
|
|
128
|
+
window.addEventListener('resize', () => this.handleResize());
|
|
114
129
|
this._textarea.addEventListener('keydown', this.handleKeyDown);
|
|
115
130
|
}
|
|
116
131
|
|
|
@@ -169,6 +184,7 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
169
184
|
|
|
170
185
|
public disconnectedCallback (): void {
|
|
171
186
|
this._textarea.removeEventListener('keydown', this.handleKeyDown);
|
|
187
|
+
window.removeEventListener('resize', () => this.handleResize());
|
|
172
188
|
}
|
|
173
189
|
|
|
174
190
|
renderLabel (label: string, maxLength?: number) {
|
|
@@ -179,6 +195,21 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
179
195
|
: nothing;
|
|
180
196
|
}
|
|
181
197
|
|
|
198
|
+
renderAssistiveText () {
|
|
199
|
+
if (!this.assistiveText) {
|
|
200
|
+
return nothing;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return html`
|
|
204
|
+
<pie-assistive-text
|
|
205
|
+
id="${assistiveTextIdValue}"
|
|
206
|
+
variant=${ifDefined(this.status)}
|
|
207
|
+
data-test-id="pie-textarea-assistive-text">
|
|
208
|
+
${this.assistiveText}
|
|
209
|
+
</pie-assistive-text>
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
|
|
182
213
|
render () {
|
|
183
214
|
const {
|
|
184
215
|
disabled,
|
|
@@ -188,33 +219,49 @@ export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implemen
|
|
|
188
219
|
autoFocus,
|
|
189
220
|
name,
|
|
190
221
|
readonly,
|
|
222
|
+
placeholder,
|
|
191
223
|
value,
|
|
192
224
|
required,
|
|
193
225
|
label,
|
|
194
226
|
maxLength,
|
|
227
|
+
status,
|
|
228
|
+
assistiveText,
|
|
195
229
|
} = this;
|
|
196
230
|
|
|
197
|
-
|
|
231
|
+
const classes = {
|
|
232
|
+
'c-textareaWrapper': true,
|
|
233
|
+
'c-textarea--disabled': disabled,
|
|
234
|
+
'c-textarea--readonly': readonly,
|
|
235
|
+
'c-textarea--error': status === 'error',
|
|
236
|
+
[`c-textarea--resize-${resize}`]: true,
|
|
237
|
+
[`c-textarea--${size}`]: true,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
return html`<div>
|
|
241
|
+
${this.renderLabel(label, maxLength)}
|
|
198
242
|
<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)}
|
|
243
|
+
class="${classMap(classes)}"
|
|
244
|
+
data-test-id="pie-textarea-wrapper">
|
|
204
245
|
<textarea
|
|
205
246
|
id="${componentSelector}"
|
|
206
247
|
data-test-id="${componentSelector}"
|
|
207
248
|
name=${ifDefined(name)}
|
|
208
249
|
autocomplete=${ifDefined(autocomplete)}
|
|
250
|
+
placeholder=${ifDefined(placeholder)}
|
|
209
251
|
.value=${live(value)}
|
|
210
252
|
?autofocus=${autoFocus}
|
|
211
253
|
?readonly=${readonly}
|
|
212
254
|
?required=${required}
|
|
213
255
|
?disabled=${disabled}
|
|
256
|
+
aria-describedby=${ifDefined(assistiveText ? assistiveTextIdValue : undefined)}
|
|
257
|
+
aria-invalid=${status === 'error' ? 'true' : 'false'}
|
|
258
|
+
aria-errormessage="${ifDefined(status === 'error' ? assistiveTextIdValue : undefined)}"
|
|
214
259
|
@input=${this.handleInput}
|
|
215
260
|
@change=${this.handleChange}
|
|
216
261
|
></textarea>
|
|
217
|
-
</div
|
|
262
|
+
</div>
|
|
263
|
+
${this.renderAssistiveText()}
|
|
264
|
+
</div>`;
|
|
218
265
|
}
|
|
219
266
|
|
|
220
267
|
// 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,108 @@
|
|
|
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);
|
|
18
|
+
--textarea-placeholder-color: var(--dt-color-content-subdued);
|
|
17
19
|
|
|
18
20
|
// Default height is two lines of text
|
|
19
|
-
--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2)
|
|
21
|
+
--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2));
|
|
20
22
|
|
|
21
|
-
line-height: 0;
|
|
23
|
+
line-height: 0;
|
|
24
|
+
padding: var(--dt-spacing-a);
|
|
25
|
+
border: var(--textarea-border-thickness) solid var(--textarea-border-color);
|
|
26
|
+
background-color: var(--textarea-background-color);
|
|
27
|
+
border-radius: var(--dt-radius-rounded-c);
|
|
28
|
+
inline-size: 100%;
|
|
22
29
|
|
|
23
30
|
textarea {
|
|
24
31
|
@include p.font-size(--dt-font-body-l-size);
|
|
25
32
|
line-height: var(--textarea-line-height);
|
|
26
33
|
font-family: var(--dt-font-body-l-family);
|
|
27
34
|
resize: var(--textarea-resize);
|
|
28
|
-
border:
|
|
35
|
+
border: none;
|
|
29
36
|
background-color: var(--textarea-background-color);
|
|
30
37
|
color: var(--textarea-content-color);
|
|
31
38
|
|
|
32
|
-
border-radius: var(--dt-radius-rounded-c);
|
|
33
39
|
block-size: var(--textarea-height);
|
|
34
40
|
max-block-size: var(--textarea-max-height);
|
|
35
41
|
min-block-size: var(--textarea-min-height);
|
|
42
|
+
inline-size: 100%;
|
|
36
43
|
|
|
37
44
|
padding-block-start: var(--textarea-padding-block);
|
|
38
45
|
padding-block-end: var(--textarea-padding-block);
|
|
39
46
|
padding-inline-start: var(--textarea-padding-inline);
|
|
40
47
|
padding-inline-end: var(--textarea-padding-inline);
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
--textarea-content-color: var(--dt-color-content-disabled);
|
|
49
|
+
&:focus {
|
|
50
|
+
box-shadow: none;
|
|
51
|
+
outline: none;
|
|
46
52
|
}
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
&::placeholder {
|
|
55
|
+
color: var(--textarea-placeholder-color);
|
|
56
|
+
|
|
57
|
+
opacity: 1; // normalize opacity for all browsers
|
|
52
58
|
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
&.c-textarea--readonly {
|
|
62
|
+
--textarea-background-color: var(--dt-color-container-subtle);
|
|
63
|
+
--textarea-border-color: var(--dt-color-interactive-form);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
&.c-textarea--disabled {
|
|
67
|
+
--textarea-background-color: var(--dt-color-disabled-01);
|
|
68
|
+
--textarea-border-color: var(--dt-color-disabled-01);
|
|
69
|
+
--textarea-content-color: var(--dt-color-content-disabled);
|
|
70
|
+
--textarea-placeholder-color: var(--dt-color-content-disabled);
|
|
71
|
+
}
|
|
53
72
|
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
@media (hover: hover) {
|
|
74
|
+
&:hover:not(.c-textarea--disabled, .c-textarea--readonly) {
|
|
75
|
+
--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
76
|
}
|
|
57
77
|
}
|
|
58
78
|
|
|
59
|
-
|
|
60
|
-
|
|
79
|
+
&:focus-within {
|
|
80
|
+
@include p.focus;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
&.c-textarea--large {
|
|
84
|
+
--textarea-padding-block: var(--dt-spacing-c);
|
|
61
85
|
}
|
|
62
86
|
|
|
63
|
-
|
|
64
|
-
--textarea-padding-block: var(--dt-spacing-
|
|
87
|
+
&.c-textarea--small {
|
|
88
|
+
--textarea-padding-block: var(--dt-spacing-a);
|
|
65
89
|
}
|
|
66
90
|
|
|
67
|
-
|
|
91
|
+
&.c-textarea--resize-manual {
|
|
68
92
|
--textarea-resize: vertical;
|
|
69
93
|
|
|
70
94
|
// Minimum is one line of text
|
|
71
|
-
--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2)
|
|
95
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2));
|
|
72
96
|
|
|
73
97
|
@media (pointer: coarse) {
|
|
74
98
|
// 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)
|
|
99
|
+
--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
100
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
101
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
78
102
|
--textarea-resize: none;
|
|
79
103
|
}
|
|
80
104
|
}
|
|
81
105
|
|
|
82
|
-
|
|
106
|
+
&.c-textarea--resize-auto {
|
|
83
107
|
// Maximum is six lines of text
|
|
84
|
-
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2)
|
|
108
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2));
|
|
85
109
|
|
|
86
110
|
// Minimum is two lines of text
|
|
87
111
|
--textarea-min-height: var(--textarea-height);
|
|
88
112
|
}
|
|
113
|
+
|
|
114
|
+
&.c-textarea--error {
|
|
115
|
+
--textarea-border-color: var(--dt-color-support-error);
|
|
116
|
+
}
|
|
89
117
|
}
|