@justeattakeaway/pie-textarea 0.3.1 → 0.5.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/README.md +11 -4
- package/custom-elements.json +198 -11
- package/dist/index.d.ts +81 -4
- package/dist/index.js +215 -33
- package/dist/react.d.ts +87 -5
- package/dist/react.js +11 -4
- package/package.json +4 -2
- package/src/defs.ts +48 -1
- package/src/index.ts +148 -11
- package/src/react.ts +11 -3
- package/src/textarea.scss +76 -9
package/README.md
CHANGED
|
@@ -72,10 +72,17 @@ import { PieTextarea } from '@justeattakeaway/pie-textarea/dist/react';
|
|
|
72
72
|
|
|
73
73
|
## Props
|
|
74
74
|
|
|
75
|
-
| Property
|
|
76
|
-
|
|
77
|
-
| `disabled` | `boolean`
|
|
78
|
-
| `size`
|
|
75
|
+
| Property | Type | Default | Description |
|
|
76
|
+
|---|---|---|---|
|
|
77
|
+
| `disabled` | `boolean` | `false`| Indicates whether or not the textarea is disabled. |
|
|
78
|
+
| `size` | `'small'`, `'medium'`, `'large'` | `'medium'` | The size of the textarea field. |
|
|
79
|
+
| `resize` | `'auto'`, `'manual'` | `'auto'` | Controls the resizing behaviour of the textarea. |
|
|
80
|
+
| `value` | `string` | `''` | The value of the textarea (used as a key/value pair in HTML forms with `name`). |
|
|
81
|
+
| `name` | `string` | `''` | The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms. |
|
|
82
|
+
| `autocomplete` | `string` | `''` | Allows the user to enable or disable autocomplete functionality on the textarea field. |
|
|
83
|
+
| `autoFocus` | `boolean` | `false` | If true, the textarea will be focused on the first render. |
|
|
84
|
+
| `readonly` | `boolean` | `false` | When true, the user cannot edit the control. Not the same as disabled. |
|
|
85
|
+
| `required` | `boolean` | `false` | If true, the textarea is required to have a value before submitting the form. If there is no value, then the component validity state will be invalid. |
|
|
79
86
|
|
|
80
87
|
In your markup or JSX, you can then use these to set the properties for the `pie-textarea` component:
|
|
81
88
|
|
package/custom-elements.json
CHANGED
|
@@ -20,13 +20,21 @@
|
|
|
20
20
|
},
|
|
21
21
|
"default": "['small', 'medium', 'large']"
|
|
22
22
|
},
|
|
23
|
+
{
|
|
24
|
+
"kind": "variable",
|
|
25
|
+
"name": "resizeModes",
|
|
26
|
+
"type": {
|
|
27
|
+
"text": "['auto', 'manual']"
|
|
28
|
+
},
|
|
29
|
+
"default": "['auto', 'manual']"
|
|
30
|
+
},
|
|
23
31
|
{
|
|
24
32
|
"kind": "variable",
|
|
25
33
|
"name": "defaultProps",
|
|
26
34
|
"type": {
|
|
27
35
|
"text": "DefaultProps"
|
|
28
36
|
},
|
|
29
|
-
"default": "{\n disabled: false,\n size: 'medium',\n}",
|
|
37
|
+
"default": "{\n disabled: false,\n size: 'medium',\n resize: 'auto',\n value: '',\n autoFocus: false,\n readonly: false,\n required: false,\n}",
|
|
30
38
|
"description": "Default values for optional properties that have default fallback values in the component."
|
|
31
39
|
}
|
|
32
40
|
],
|
|
@@ -39,6 +47,14 @@
|
|
|
39
47
|
"module": "src/defs.js"
|
|
40
48
|
}
|
|
41
49
|
},
|
|
50
|
+
{
|
|
51
|
+
"kind": "js",
|
|
52
|
+
"name": "resizeModes",
|
|
53
|
+
"declaration": {
|
|
54
|
+
"name": "resizeModes",
|
|
55
|
+
"module": "src/defs.js"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
42
58
|
{
|
|
43
59
|
"kind": "js",
|
|
44
60
|
"name": "defaultProps",
|
|
@@ -67,12 +83,15 @@
|
|
|
67
83
|
"static": true,
|
|
68
84
|
"default": "{ ...LitElement.shadowRootOptions, delegatesFocus: true }"
|
|
69
85
|
},
|
|
86
|
+
{
|
|
87
|
+
"kind": "field",
|
|
88
|
+
"name": "value",
|
|
89
|
+
"privacy": "public",
|
|
90
|
+
"attribute": "value"
|
|
91
|
+
},
|
|
70
92
|
{
|
|
71
93
|
"kind": "field",
|
|
72
94
|
"name": "disabled",
|
|
73
|
-
"type": {
|
|
74
|
-
"text": "TextareaProps['disabled'] | undefined"
|
|
75
|
-
},
|
|
76
95
|
"privacy": "public",
|
|
77
96
|
"attribute": "disabled",
|
|
78
97
|
"reflects": true
|
|
@@ -80,30 +99,198 @@
|
|
|
80
99
|
{
|
|
81
100
|
"kind": "field",
|
|
82
101
|
"name": "size",
|
|
102
|
+
"privacy": "public",
|
|
103
|
+
"attribute": "size"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"kind": "field",
|
|
107
|
+
"name": "resize",
|
|
108
|
+
"privacy": "public",
|
|
109
|
+
"attribute": "resize"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"kind": "field",
|
|
113
|
+
"name": "readonly",
|
|
114
|
+
"privacy": "public",
|
|
115
|
+
"attribute": "readonly"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"kind": "field",
|
|
119
|
+
"name": "autoFocus",
|
|
120
|
+
"privacy": "public",
|
|
121
|
+
"attribute": "autoFocus"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"kind": "field",
|
|
125
|
+
"name": "required",
|
|
126
|
+
"privacy": "public",
|
|
127
|
+
"attribute": "required"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"kind": "field",
|
|
131
|
+
"name": "name",
|
|
83
132
|
"type": {
|
|
84
|
-
"text": "TextareaProps['
|
|
133
|
+
"text": "TextareaProps['name'] | undefined"
|
|
85
134
|
},
|
|
86
135
|
"privacy": "public",
|
|
87
|
-
"attribute": "
|
|
136
|
+
"attribute": "name"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"kind": "field",
|
|
140
|
+
"name": "autocomplete",
|
|
141
|
+
"type": {
|
|
142
|
+
"text": "TextareaProps['autocomplete'] | undefined"
|
|
143
|
+
},
|
|
144
|
+
"privacy": "public",
|
|
145
|
+
"attribute": "autocomplete"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"kind": "field",
|
|
149
|
+
"name": "_textarea",
|
|
150
|
+
"type": {
|
|
151
|
+
"text": "HTMLTextAreaElement"
|
|
152
|
+
},
|
|
153
|
+
"privacy": "private"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"kind": "field",
|
|
157
|
+
"name": "_throttledResize",
|
|
158
|
+
"privacy": "private"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"kind": "field",
|
|
162
|
+
"name": "validity",
|
|
163
|
+
"type": {
|
|
164
|
+
"text": "ValidityState"
|
|
165
|
+
},
|
|
166
|
+
"privacy": "public",
|
|
167
|
+
"description": "(Read-only) returns a ValidityState with the validity states that this element is in.\nhttps://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity",
|
|
168
|
+
"readonly": true
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"kind": "method",
|
|
172
|
+
"name": "formDisabledCallback",
|
|
173
|
+
"privacy": "public",
|
|
174
|
+
"return": {
|
|
175
|
+
"type": {
|
|
176
|
+
"text": "void"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
"parameters": [
|
|
180
|
+
{
|
|
181
|
+
"name": "disabled",
|
|
182
|
+
"type": {
|
|
183
|
+
"text": "boolean"
|
|
184
|
+
},
|
|
185
|
+
"description": "The latest disabled state of the input."
|
|
186
|
+
}
|
|
187
|
+
],
|
|
188
|
+
"description": "Called after the disabled state of the element changes,\neither because the disabled attribute of this element was added or removed;\nor because the disabled state changed on a <fieldset> that's an ancestor of this element."
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
"kind": "method",
|
|
192
|
+
"name": "formResetCallback",
|
|
193
|
+
"privacy": "public",
|
|
194
|
+
"return": {
|
|
195
|
+
"type": {
|
|
196
|
+
"text": "void"
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
"description": "Called when the form that owns this component is reset.\nResets the value to the default value."
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"kind": "method",
|
|
203
|
+
"name": "handleResize",
|
|
204
|
+
"privacy": "private"
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
"kind": "field",
|
|
208
|
+
"name": "handleInput",
|
|
209
|
+
"privacy": "private",
|
|
210
|
+
"description": "Handles data processing in response to the input event. The native input event is left to bubble up.",
|
|
211
|
+
"parameters": [
|
|
212
|
+
{
|
|
213
|
+
"description": "The input event.",
|
|
214
|
+
"name": "event"
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"kind": "field",
|
|
220
|
+
"name": "handleChange",
|
|
221
|
+
"privacy": "private"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"kind": "field",
|
|
225
|
+
"name": "handleKeyDown",
|
|
226
|
+
"privacy": "private"
|
|
88
227
|
}
|
|
89
228
|
],
|
|
90
|
-
"
|
|
229
|
+
"events": [
|
|
91
230
|
{
|
|
92
|
-
"name": "disabled",
|
|
93
231
|
"type": {
|
|
94
|
-
"text": "
|
|
232
|
+
"text": "InputEvent"
|
|
95
233
|
},
|
|
234
|
+
"description": "when the textarea value is changed.",
|
|
235
|
+
"name": "input"
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
"type": {
|
|
239
|
+
"text": "CustomEvent"
|
|
240
|
+
},
|
|
241
|
+
"description": "when the textarea value is changed.",
|
|
242
|
+
"name": "change"
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
"attributes": [
|
|
246
|
+
{
|
|
247
|
+
"name": "value",
|
|
248
|
+
"fieldName": "value"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
"name": "disabled",
|
|
96
252
|
"fieldName": "disabled"
|
|
97
253
|
},
|
|
98
254
|
{
|
|
99
255
|
"name": "size",
|
|
256
|
+
"fieldName": "size"
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
"name": "resize",
|
|
260
|
+
"fieldName": "resize"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"name": "readonly",
|
|
264
|
+
"fieldName": "readonly"
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "autoFocus",
|
|
268
|
+
"fieldName": "autoFocus"
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"name": "required",
|
|
272
|
+
"fieldName": "required"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"name": "name",
|
|
100
276
|
"type": {
|
|
101
|
-
"text": "TextareaProps['
|
|
277
|
+
"text": "TextareaProps['name'] | undefined"
|
|
102
278
|
},
|
|
103
|
-
"fieldName": "
|
|
279
|
+
"fieldName": "name"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"name": "autocomplete",
|
|
283
|
+
"type": {
|
|
284
|
+
"text": "TextareaProps['autocomplete'] | undefined"
|
|
285
|
+
},
|
|
286
|
+
"fieldName": "autocomplete"
|
|
104
287
|
}
|
|
105
288
|
],
|
|
106
289
|
"mixins": [
|
|
290
|
+
{
|
|
291
|
+
"name": "FormControlMixin",
|
|
292
|
+
"package": "@justeattakeaway/pie-webc-core"
|
|
293
|
+
},
|
|
107
294
|
{
|
|
108
295
|
"name": "RtlMixin",
|
|
109
296
|
"package": "@justeattakeaway/pie-webc-core"
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
2
2
|
import type { CSSResult } from 'lit';
|
|
3
|
+
import type { FormControlInterface } from '@justeattakeaway/pie-webc-core';
|
|
3
4
|
import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
|
|
4
5
|
import type { LitElement } from 'lit';
|
|
6
|
+
import type { PropertyValues } from 'lit';
|
|
5
7
|
import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
|
|
6
8
|
import type { TemplateResult } from 'lit-html';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
10
12
|
*/
|
|
11
|
-
declare type DefaultProps = ComponentDefaultProps<TextareaProps
|
|
13
|
+
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete'>>;
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -17,6 +19,8 @@ export declare const defaultProps: DefaultProps;
|
|
|
17
19
|
|
|
18
20
|
/**
|
|
19
21
|
* @tagname pie-textarea
|
|
22
|
+
* @event {InputEvent} input - when the textarea value is changed.
|
|
23
|
+
* @event {CustomEvent} change - when the textarea value is changed.
|
|
20
24
|
*/
|
|
21
25
|
export declare class PieTextarea extends PieTextarea_base implements TextareaProps {
|
|
22
26
|
static shadowRootOptions: {
|
|
@@ -24,13 +28,52 @@ export declare class PieTextarea extends PieTextarea_base implements TextareaPro
|
|
|
24
28
|
mode: ShadowRootMode;
|
|
25
29
|
slotAssignment?: SlotAssignmentMode | undefined;
|
|
26
30
|
};
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
value: string;
|
|
32
|
+
disabled: boolean;
|
|
33
|
+
size: "small" | "medium" | "large";
|
|
34
|
+
resize: "auto" | "manual";
|
|
35
|
+
readonly: boolean;
|
|
36
|
+
autoFocus: boolean;
|
|
37
|
+
required: boolean;
|
|
38
|
+
name?: TextareaProps['name'];
|
|
39
|
+
autocomplete?: TextareaProps['autocomplete'];
|
|
40
|
+
private _textarea;
|
|
41
|
+
private _throttledResize;
|
|
42
|
+
/**
|
|
43
|
+
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
44
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
45
|
+
*/
|
|
46
|
+
get validity(): ValidityState;
|
|
47
|
+
/**
|
|
48
|
+
* Called after the disabled state of the element changes,
|
|
49
|
+
* either because the disabled attribute of this element was added or removed;
|
|
50
|
+
* or because the disabled state changed on a <fieldset> that's an ancestor of this element.
|
|
51
|
+
* @param disabled - The latest disabled state of the input.
|
|
52
|
+
*/
|
|
53
|
+
formDisabledCallback(disabled: boolean): void;
|
|
54
|
+
/**
|
|
55
|
+
* Called when the form that owns this component is reset.
|
|
56
|
+
* Resets the value to the default value.
|
|
57
|
+
*/
|
|
58
|
+
formResetCallback(): void;
|
|
59
|
+
protected firstUpdated(): void;
|
|
60
|
+
private handleResize;
|
|
61
|
+
protected updated(changedProperties: PropertyValues<this>): void;
|
|
62
|
+
/**
|
|
63
|
+
* Handles data processing in response to the input event. The native input event is left to bubble up.
|
|
64
|
+
* @param event - The input event.
|
|
65
|
+
*/
|
|
66
|
+
private handleInput;
|
|
67
|
+
private handleChange;
|
|
68
|
+
private handleKeyDown;
|
|
69
|
+
disconnectedCallback(): void;
|
|
29
70
|
render(): TemplateResult<1>;
|
|
30
71
|
static styles: CSSResult;
|
|
31
72
|
}
|
|
32
73
|
|
|
33
|
-
declare const PieTextarea_base: GenericConstructor<RTLInterface> & typeof LitElement;
|
|
74
|
+
declare const PieTextarea_base: GenericConstructor<FormControlInterface> & GenericConstructor<RTLInterface> & typeof LitElement;
|
|
75
|
+
|
|
76
|
+
export declare const resizeModes: readonly ["auto", "manual"];
|
|
34
77
|
|
|
35
78
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
36
79
|
|
|
@@ -43,6 +86,40 @@ export declare interface TextareaProps {
|
|
|
43
86
|
* The size of the textarea field. Can be `small`, `medium` or `large`. Defaults to `medium`.
|
|
44
87
|
*/
|
|
45
88
|
size?: typeof sizes[number];
|
|
89
|
+
/**
|
|
90
|
+
* The resize mode of the textarea. Can be `auto` or `manual`. Defaults to `auto`.
|
|
91
|
+
* When set to `auto`, the textarea will resize vertically as needed.
|
|
92
|
+
* When set to `manual`, the textarea will not resize automatically but can be resized by the user.
|
|
93
|
+
*/
|
|
94
|
+
resize?: typeof resizeModes[number];
|
|
95
|
+
/**
|
|
96
|
+
* The value of the textarea (used as a key/value pair in HTML forms with `name`).
|
|
97
|
+
*/
|
|
98
|
+
value: string;
|
|
99
|
+
/**
|
|
100
|
+
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
101
|
+
*/
|
|
102
|
+
name?: string;
|
|
103
|
+
/**
|
|
104
|
+
* Allows the user to enable or disable autocomplete functionality on the textarea field.
|
|
105
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for more information and values.
|
|
106
|
+
*/
|
|
107
|
+
autocomplete?: string;
|
|
108
|
+
/**
|
|
109
|
+
* If true, the textarea will be focused on the first render.
|
|
110
|
+
* No more than one element in the document or dialog may have the autofocus attribute. If applied to multiple elements the first one will receive focus.
|
|
111
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) for more information.
|
|
112
|
+
*/
|
|
113
|
+
autoFocus?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* When true, the user cannot edit the control. Not the same as disabled.
|
|
116
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.
|
|
117
|
+
*/
|
|
118
|
+
readonly?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* If true, the textarea is required to have a value before submitting the form. If there is no value, then the component validity state will be invalid.
|
|
121
|
+
*/
|
|
122
|
+
required?: boolean;
|
|
46
123
|
}
|
|
47
124
|
|
|
48
125
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,51 +1,233 @@
|
|
|
1
|
-
import { LitElement as
|
|
2
|
-
import { property as
|
|
3
|
-
import { ifDefined as
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { LitElement as F, html as q, unsafeCSS as B } from "lit";
|
|
2
|
+
import { property as p, query as N } from "lit/decorators.js";
|
|
3
|
+
import { ifDefined as W } from "lit/directives/if-defined.js";
|
|
4
|
+
import { live as V } from "lit/directives/live.js";
|
|
5
|
+
import { FormControlMixin as A, RtlMixin as K, wrapNativeEvent as G, validPropertyValues as I, defineCustomElement as H } from "@justeattakeaway/pie-webc-core";
|
|
6
|
+
var m = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
|
|
7
|
+
function U(e) {
|
|
8
|
+
return e && e.__esModule && Object.prototype.hasOwnProperty.call(e, "default") ? e.default : e;
|
|
9
|
+
}
|
|
10
|
+
var R = "Expected a function", w = 0 / 0, X = "[object Symbol]", J = /^\s+|\s+$/g, Q = /^[-+]0x[0-9a-f]+$/i, Y = /^0b[01]+$/i, Z = /^0o[0-7]+$/i, ee = parseInt, te = typeof m == "object" && m && m.Object === Object && m, ae = typeof self == "object" && self && self.Object === Object && self, re = te || ae || Function("return this")(), ie = Object.prototype, ne = ie.toString, oe = Math.max, se = Math.min, j = function() {
|
|
11
|
+
return re.Date.now();
|
|
12
|
+
};
|
|
13
|
+
function le(e, t, a) {
|
|
14
|
+
var n, r, d, l, o, h, x = 0, T = !1, v = !1, z = !0;
|
|
15
|
+
if (typeof e != "function")
|
|
16
|
+
throw new TypeError(R);
|
|
17
|
+
t = C(t) || 0, y(a) && (T = !!a.leading, v = "maxWait" in a, d = v ? oe(C(a.maxWait) || 0, t) : d, z = "trailing" in a ? !!a.trailing : z);
|
|
18
|
+
function k(i) {
|
|
19
|
+
var f = n, g = r;
|
|
20
|
+
return n = r = void 0, x = i, l = e.apply(g, f), l;
|
|
21
|
+
}
|
|
22
|
+
function D(i) {
|
|
23
|
+
return x = i, o = setTimeout(b, t), T ? k(i) : l;
|
|
24
|
+
}
|
|
25
|
+
function P(i) {
|
|
26
|
+
var f = i - h, g = i - x, $ = t - f;
|
|
27
|
+
return v ? se($, d - g) : $;
|
|
28
|
+
}
|
|
29
|
+
function E(i) {
|
|
30
|
+
var f = i - h, g = i - x;
|
|
31
|
+
return h === void 0 || f >= t || f < 0 || v && g >= d;
|
|
32
|
+
}
|
|
33
|
+
function b() {
|
|
34
|
+
var i = j();
|
|
35
|
+
if (E(i))
|
|
36
|
+
return S(i);
|
|
37
|
+
o = setTimeout(b, P(i));
|
|
38
|
+
}
|
|
39
|
+
function S(i) {
|
|
40
|
+
return o = void 0, z && n ? k(i) : (n = r = void 0, l);
|
|
41
|
+
}
|
|
42
|
+
function L() {
|
|
43
|
+
o !== void 0 && clearTimeout(o), x = 0, n = h = r = o = void 0;
|
|
44
|
+
}
|
|
45
|
+
function M() {
|
|
46
|
+
return o === void 0 ? l : S(j());
|
|
47
|
+
}
|
|
48
|
+
function _() {
|
|
49
|
+
var i = j(), f = E(i);
|
|
50
|
+
if (n = arguments, r = this, h = i, f) {
|
|
51
|
+
if (o === void 0)
|
|
52
|
+
return D(h);
|
|
53
|
+
if (v)
|
|
54
|
+
return o = setTimeout(b, t), k(h);
|
|
55
|
+
}
|
|
56
|
+
return o === void 0 && (o = setTimeout(b, t)), l;
|
|
57
|
+
}
|
|
58
|
+
return _.cancel = L, _.flush = M, _;
|
|
59
|
+
}
|
|
60
|
+
function de(e, t, a) {
|
|
61
|
+
var n = !0, r = !0;
|
|
62
|
+
if (typeof e != "function")
|
|
63
|
+
throw new TypeError(R);
|
|
64
|
+
return y(a) && (n = "leading" in a ? !!a.leading : n, r = "trailing" in a ? !!a.trailing : r), le(e, t, {
|
|
65
|
+
leading: n,
|
|
66
|
+
maxWait: t,
|
|
67
|
+
trailing: r
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function y(e) {
|
|
71
|
+
var t = typeof e;
|
|
72
|
+
return !!e && (t == "object" || t == "function");
|
|
73
|
+
}
|
|
74
|
+
function ce(e) {
|
|
75
|
+
return !!e && typeof e == "object";
|
|
76
|
+
}
|
|
77
|
+
function ue(e) {
|
|
78
|
+
return typeof e == "symbol" || ce(e) && ne.call(e) == X;
|
|
79
|
+
}
|
|
80
|
+
function C(e) {
|
|
81
|
+
if (typeof e == "number")
|
|
82
|
+
return e;
|
|
83
|
+
if (ue(e))
|
|
84
|
+
return w;
|
|
85
|
+
if (y(e)) {
|
|
86
|
+
var t = typeof e.valueOf == "function" ? e.valueOf() : e;
|
|
87
|
+
e = y(t) ? t + "" : t;
|
|
88
|
+
}
|
|
89
|
+
if (typeof e != "string")
|
|
90
|
+
return e === 0 ? e : +e;
|
|
91
|
+
e = e.replace(J, "");
|
|
92
|
+
var a = Y.test(e);
|
|
93
|
+
return a || Z.test(e) ? ee(e.slice(2), a ? 2 : 8) : Q.test(e) ? w : +e;
|
|
94
|
+
}
|
|
95
|
+
var he = de;
|
|
96
|
+
const pe = /* @__PURE__ */ U(he), fe = `*,*: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-d);--textarea-padding-block: var(--dt-spacing-c);--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) + (var(--textarea-border-thickness) * 2));line-height:0}.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:var(--textarea-border-thickness) solid var(--textarea-border-color);background-color:var(--textarea-background-color);color:var(--textarea-content-color);border-radius:var(--dt-radius-rounded-c);block-size:var(--textarea-height);max-block-size:var(--textarea-max-height);min-block-size:var(--textarea-min-height);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[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 textarea:hover:not([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 textarea:focus-visible{box-shadow:0 0 0 2px var(--dt-color-focus-inner),0 0 0 4px var(--dt-color-focus-outer);outline:none}.c-textareaWrapper[data-pie-size=large]{--textarea-padding-block: var(--dt-spacing-d)}.c-textareaWrapper[data-pie-size=small]{--textarea-padding-block: var(--dt-spacing-b)}.c-textareaWrapper[data-pie-resize=manual]{--textarea-resize: vertical;--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2))}@media (pointer: coarse){.c-textareaWrapper[data-pie-resize=manual]{--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));--textarea-resize: none}}.c-textareaWrapper[data-pie-resize=auto]{--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));--textarea-min-height: var(--textarea-height)}
|
|
97
|
+
`, xe = ["small", "medium", "large"], ve = ["auto", "manual"], c = {
|
|
7
98
|
disabled: !1,
|
|
8
|
-
size: "medium"
|
|
99
|
+
size: "medium",
|
|
100
|
+
resize: "auto",
|
|
101
|
+
value: "",
|
|
102
|
+
autoFocus: !1,
|
|
103
|
+
readonly: !1,
|
|
104
|
+
required: !1
|
|
9
105
|
};
|
|
10
|
-
var
|
|
11
|
-
for (var
|
|
12
|
-
(
|
|
13
|
-
return
|
|
106
|
+
var ge = Object.defineProperty, be = Object.getOwnPropertyDescriptor, u = (e, t, a, n) => {
|
|
107
|
+
for (var r = n > 1 ? void 0 : n ? be(t, a) : t, d = e.length - 1, l; d >= 0; d--)
|
|
108
|
+
(l = e[d]) && (r = (n ? l(t, a, r) : l(r)) || r);
|
|
109
|
+
return n && r && ge(t, a, r), r;
|
|
14
110
|
};
|
|
15
|
-
const
|
|
16
|
-
class
|
|
111
|
+
const O = "pie-textarea";
|
|
112
|
+
class s extends A(K(F)) {
|
|
17
113
|
constructor() {
|
|
18
|
-
super(...arguments), this.size =
|
|
114
|
+
super(...arguments), this.value = c.value, this.disabled = c.disabled, this.size = c.size, this.resize = c.resize, this.readonly = c.readonly, this.autoFocus = c.autoFocus, this.required = c.required, this._throttledResize = pe(() => {
|
|
115
|
+
this.resize === "auto" && (this._textarea.style.height = "auto", this._textarea.style.height = `${this._textarea.scrollHeight + 2}px`);
|
|
116
|
+
}, 100), this.handleInput = (t) => {
|
|
117
|
+
this.value = t.target.value, this._internals.setFormValue(this.value), this.handleResize();
|
|
118
|
+
}, this.handleChange = (t) => {
|
|
119
|
+
const a = G(t);
|
|
120
|
+
this.dispatchEvent(a);
|
|
121
|
+
}, this.handleKeyDown = (t) => {
|
|
122
|
+
t.key === "Enter" && t.stopPropagation();
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
127
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
128
|
+
*/
|
|
129
|
+
get validity() {
|
|
130
|
+
return this._textarea.validity;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Called after the disabled state of the element changes,
|
|
134
|
+
* either because the disabled attribute of this element was added or removed;
|
|
135
|
+
* or because the disabled state changed on a <fieldset> that's an ancestor of this element.
|
|
136
|
+
* @param disabled - The latest disabled state of the input.
|
|
137
|
+
*/
|
|
138
|
+
formDisabledCallback(t) {
|
|
139
|
+
this.disabled = t;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Called when the form that owns this component is reset.
|
|
143
|
+
* Resets the value to the default value.
|
|
144
|
+
*/
|
|
145
|
+
formResetCallback() {
|
|
146
|
+
this.value = c.value, this._internals.setFormValue(this.value);
|
|
147
|
+
}
|
|
148
|
+
firstUpdated() {
|
|
149
|
+
this._internals.setFormValue(this.value), this._textarea.addEventListener("keydown", this.handleKeyDown);
|
|
150
|
+
}
|
|
151
|
+
handleResize() {
|
|
152
|
+
this._throttledResize();
|
|
153
|
+
}
|
|
154
|
+
updated(t) {
|
|
155
|
+
this.resize === "auto" && (t.has("resize") || t.has("size")) && this.handleResize(), t.has("value") && this._internals.setFormValue(this.value);
|
|
156
|
+
}
|
|
157
|
+
disconnectedCallback() {
|
|
158
|
+
this._textarea.removeEventListener("keydown", this.handleKeyDown);
|
|
19
159
|
}
|
|
20
160
|
render() {
|
|
21
161
|
const {
|
|
22
162
|
disabled: t,
|
|
23
|
-
|
|
163
|
+
resize: a,
|
|
164
|
+
size: n,
|
|
165
|
+
autocomplete: r,
|
|
166
|
+
autoFocus: d,
|
|
167
|
+
name: l,
|
|
168
|
+
readonly: o,
|
|
169
|
+
value: h,
|
|
170
|
+
required: x
|
|
24
171
|
} = this;
|
|
25
|
-
return
|
|
172
|
+
return q`
|
|
26
173
|
<div
|
|
27
|
-
class="c-
|
|
28
|
-
data-test-id="pie-textarea-
|
|
29
|
-
data-pie-size
|
|
174
|
+
class="c-textareaWrapper"
|
|
175
|
+
data-test-id="pie-textarea-wrapper"
|
|
176
|
+
data-pie-size="${n}"
|
|
177
|
+
data-pie-resize="${a}">
|
|
30
178
|
<textarea
|
|
31
|
-
|
|
179
|
+
name=${W(l)}
|
|
180
|
+
autocomplete=${W(r)}
|
|
181
|
+
.value=${V(h)}
|
|
182
|
+
?autofocus=${d}
|
|
183
|
+
?readonly=${o}
|
|
184
|
+
?required=${x}
|
|
32
185
|
?disabled=${t}
|
|
186
|
+
@input=${this.handleInput}
|
|
187
|
+
@change=${this.handleChange}
|
|
188
|
+
data-test-id="pie-textarea"
|
|
33
189
|
></textarea>
|
|
34
190
|
</div>`;
|
|
35
191
|
}
|
|
36
192
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
],
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
193
|
+
s.shadowRootOptions = { ...F.shadowRootOptions, delegatesFocus: !0 };
|
|
194
|
+
s.styles = B(fe);
|
|
195
|
+
u([
|
|
196
|
+
p({ type: String })
|
|
197
|
+
], s.prototype, "value", 2);
|
|
198
|
+
u([
|
|
199
|
+
p({ type: Boolean, reflect: !0 })
|
|
200
|
+
], s.prototype, "disabled", 2);
|
|
201
|
+
u([
|
|
202
|
+
p({ type: String }),
|
|
203
|
+
I(O, xe, c.size)
|
|
204
|
+
], s.prototype, "size", 2);
|
|
205
|
+
u([
|
|
206
|
+
p({ type: String }),
|
|
207
|
+
I(O, ve, c.resize)
|
|
208
|
+
], s.prototype, "resize", 2);
|
|
209
|
+
u([
|
|
210
|
+
p({ type: Boolean })
|
|
211
|
+
], s.prototype, "readonly", 2);
|
|
212
|
+
u([
|
|
213
|
+
p({ type: Boolean })
|
|
214
|
+
], s.prototype, "autoFocus", 2);
|
|
215
|
+
u([
|
|
216
|
+
p({ type: Boolean })
|
|
217
|
+
], s.prototype, "required", 2);
|
|
218
|
+
u([
|
|
219
|
+
p({ type: String })
|
|
220
|
+
], s.prototype, "name", 2);
|
|
221
|
+
u([
|
|
222
|
+
p({ type: String })
|
|
223
|
+
], s.prototype, "autocomplete", 2);
|
|
224
|
+
u([
|
|
225
|
+
N("textarea")
|
|
226
|
+
], s.prototype, "_textarea", 2);
|
|
227
|
+
H(O, s);
|
|
47
228
|
export {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
229
|
+
s as PieTextarea,
|
|
230
|
+
c as defaultProps,
|
|
231
|
+
ve as resizeModes,
|
|
232
|
+
xe as sizes
|
|
51
233
|
};
|
package/dist/react.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
2
2
|
import type { CSSResult } from 'lit';
|
|
3
|
+
import type { FormControlInterface } from '@justeattakeaway/pie-webc-core';
|
|
3
4
|
import type { GenericConstructor } from '@justeattakeaway/pie-webc-core';
|
|
4
5
|
import type { LitElement } from 'lit';
|
|
6
|
+
import type { PropertyValues } from 'lit';
|
|
5
7
|
import * as React_2 from 'react';
|
|
6
8
|
import type { RTLInterface } from '@justeattakeaway/pie-webc-core';
|
|
7
9
|
import type { TemplateResult } from 'lit-html';
|
|
@@ -9,17 +11,19 @@ import type { TemplateResult } from 'lit-html';
|
|
|
9
11
|
/**
|
|
10
12
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
11
13
|
*/
|
|
12
|
-
declare type DefaultProps = ComponentDefaultProps<TextareaProps
|
|
14
|
+
declare type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name' | 'autocomplete'>>;
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Default values for optional properties that have default fallback values in the component.
|
|
16
18
|
*/
|
|
17
19
|
export declare const defaultProps: DefaultProps;
|
|
18
20
|
|
|
19
|
-
export declare const PieTextarea: React_2.ForwardRefExoticComponent<TextareaProps & React_2.RefAttributes<PieTextarea_2> & ReactBaseType>;
|
|
21
|
+
export declare const PieTextarea: React_2.ForwardRefExoticComponent<TextareaProps & React_2.RefAttributes<PieTextarea_2> & PieTextareaEvents & ReactBaseType>;
|
|
20
22
|
|
|
21
23
|
/**
|
|
22
24
|
* @tagname pie-textarea
|
|
25
|
+
* @event {InputEvent} input - when the textarea value is changed.
|
|
26
|
+
* @event {CustomEvent} change - when the textarea value is changed.
|
|
23
27
|
*/
|
|
24
28
|
declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
25
29
|
static shadowRootOptions: {
|
|
@@ -27,16 +31,60 @@ declare class PieTextarea_2 extends PieTextarea_base implements TextareaProps {
|
|
|
27
31
|
mode: ShadowRootMode;
|
|
28
32
|
slotAssignment?: SlotAssignmentMode | undefined;
|
|
29
33
|
};
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
value: string;
|
|
35
|
+
disabled: boolean;
|
|
36
|
+
size: "small" | "medium" | "large";
|
|
37
|
+
resize: "auto" | "manual";
|
|
38
|
+
readonly: boolean;
|
|
39
|
+
autoFocus: boolean;
|
|
40
|
+
required: boolean;
|
|
41
|
+
name?: TextareaProps['name'];
|
|
42
|
+
autocomplete?: TextareaProps['autocomplete'];
|
|
43
|
+
private _textarea;
|
|
44
|
+
private _throttledResize;
|
|
45
|
+
/**
|
|
46
|
+
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
47
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
48
|
+
*/
|
|
49
|
+
get validity(): ValidityState;
|
|
50
|
+
/**
|
|
51
|
+
* Called after the disabled state of the element changes,
|
|
52
|
+
* either because the disabled attribute of this element was added or removed;
|
|
53
|
+
* or because the disabled state changed on a <fieldset> that's an ancestor of this element.
|
|
54
|
+
* @param disabled - The latest disabled state of the input.
|
|
55
|
+
*/
|
|
56
|
+
formDisabledCallback(disabled: boolean): void;
|
|
57
|
+
/**
|
|
58
|
+
* Called when the form that owns this component is reset.
|
|
59
|
+
* Resets the value to the default value.
|
|
60
|
+
*/
|
|
61
|
+
formResetCallback(): void;
|
|
62
|
+
protected firstUpdated(): void;
|
|
63
|
+
private handleResize;
|
|
64
|
+
protected updated(changedProperties: PropertyValues<this>): void;
|
|
65
|
+
/**
|
|
66
|
+
* Handles data processing in response to the input event. The native input event is left to bubble up.
|
|
67
|
+
* @param event - The input event.
|
|
68
|
+
*/
|
|
69
|
+
private handleInput;
|
|
70
|
+
private handleChange;
|
|
71
|
+
private handleKeyDown;
|
|
72
|
+
disconnectedCallback(): void;
|
|
32
73
|
render(): TemplateResult<1>;
|
|
33
74
|
static styles: CSSResult;
|
|
34
75
|
}
|
|
35
76
|
|
|
36
|
-
declare const PieTextarea_base: GenericConstructor<RTLInterface> & typeof LitElement;
|
|
77
|
+
declare const PieTextarea_base: GenericConstructor<FormControlInterface> & GenericConstructor<RTLInterface> & typeof LitElement;
|
|
78
|
+
|
|
79
|
+
declare type PieTextareaEvents = {
|
|
80
|
+
onInput?: (event: InputEvent) => void;
|
|
81
|
+
onChange?: (event: CustomEvent) => void;
|
|
82
|
+
};
|
|
37
83
|
|
|
38
84
|
declare type ReactBaseType = React_2.HTMLAttributes<HTMLTextAreaElement>;
|
|
39
85
|
|
|
86
|
+
export declare const resizeModes: readonly ["auto", "manual"];
|
|
87
|
+
|
|
40
88
|
export declare const sizes: readonly ["small", "medium", "large"];
|
|
41
89
|
|
|
42
90
|
export declare interface TextareaProps {
|
|
@@ -48,6 +96,40 @@ export declare interface TextareaProps {
|
|
|
48
96
|
* The size of the textarea field. Can be `small`, `medium` or `large`. Defaults to `medium`.
|
|
49
97
|
*/
|
|
50
98
|
size?: typeof sizes[number];
|
|
99
|
+
/**
|
|
100
|
+
* The resize mode of the textarea. Can be `auto` or `manual`. Defaults to `auto`.
|
|
101
|
+
* When set to `auto`, the textarea will resize vertically as needed.
|
|
102
|
+
* When set to `manual`, the textarea will not resize automatically but can be resized by the user.
|
|
103
|
+
*/
|
|
104
|
+
resize?: typeof resizeModes[number];
|
|
105
|
+
/**
|
|
106
|
+
* The value of the textarea (used as a key/value pair in HTML forms with `name`).
|
|
107
|
+
*/
|
|
108
|
+
value: string;
|
|
109
|
+
/**
|
|
110
|
+
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
111
|
+
*/
|
|
112
|
+
name?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Allows the user to enable or disable autocomplete functionality on the textarea field.
|
|
115
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for more information and values.
|
|
116
|
+
*/
|
|
117
|
+
autocomplete?: string;
|
|
118
|
+
/**
|
|
119
|
+
* If true, the textarea will be focused on the first render.
|
|
120
|
+
* No more than one element in the document or dialog may have the autofocus attribute. If applied to multiple elements the first one will receive focus.
|
|
121
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) for more information.
|
|
122
|
+
*/
|
|
123
|
+
autoFocus?: boolean;
|
|
124
|
+
/**
|
|
125
|
+
* When true, the user cannot edit the control. Not the same as disabled.
|
|
126
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.
|
|
127
|
+
*/
|
|
128
|
+
readonly?: boolean;
|
|
129
|
+
/**
|
|
130
|
+
* If true, the textarea is required to have a value before submitting the form. If there is no value, then the component validity state will be invalid.
|
|
131
|
+
*/
|
|
132
|
+
required?: boolean;
|
|
51
133
|
}
|
|
52
134
|
|
|
53
135
|
export { }
|
package/dist/react.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
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 T, resizeModes as l, sizes as d } from "./index.js";
|
|
5
5
|
import "lit";
|
|
6
6
|
import "lit/decorators.js";
|
|
7
7
|
import "lit/directives/if-defined.js";
|
|
8
|
+
import "lit/directives/live.js";
|
|
8
9
|
import "@justeattakeaway/pie-webc-core";
|
|
9
10
|
const r = t({
|
|
10
11
|
displayName: "PieTextarea",
|
|
11
12
|
elementClass: a,
|
|
12
13
|
react: e,
|
|
13
14
|
tagName: "pie-textarea",
|
|
14
|
-
events: {
|
|
15
|
+
events: {
|
|
16
|
+
onInput: "input",
|
|
17
|
+
// when the textarea value is changed.
|
|
18
|
+
onChange: "change"
|
|
19
|
+
// when the textarea value is changed.
|
|
20
|
+
}
|
|
15
21
|
}), c = r;
|
|
16
22
|
export {
|
|
17
23
|
c as PieTextarea,
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
T as defaultProps,
|
|
25
|
+
l as resizeModes,
|
|
26
|
+
d as sizes
|
|
20
27
|
};
|
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.5.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -37,10 +37,12 @@
|
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"@custom-elements-manifest/analyzer": "0.9.0",
|
|
39
39
|
"@justeattakeaway/pie-components-config": "0.16.0",
|
|
40
|
+
"@types/lodash.throttle": "4.1.9",
|
|
40
41
|
"cem-plugin-module-file-extensions": "0.0.5"
|
|
41
42
|
},
|
|
42
43
|
"dependencies": {
|
|
43
|
-
"@justeattakeaway/pie-webc-core": "0.24.0"
|
|
44
|
+
"@justeattakeaway/pie-webc-core": "0.24.0",
|
|
45
|
+
"lodash.throttle": "4.1.1"
|
|
44
46
|
},
|
|
45
47
|
"volta": {
|
|
46
48
|
"extends": "../../../package.json"
|
package/src/defs.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ComponentDefaultProps } from '@justeattakeaway/pie-webc-core';
|
|
2
2
|
|
|
3
3
|
export const sizes = ['small', 'medium', 'large'] as const;
|
|
4
|
+
export const resizeModes = ['auto', 'manual'] as const;
|
|
4
5
|
|
|
5
6
|
export interface TextareaProps {
|
|
6
7
|
/**
|
|
@@ -12,12 +13,53 @@ export interface TextareaProps {
|
|
|
12
13
|
* The size of the textarea field. Can be `small`, `medium` or `large`. Defaults to `medium`.
|
|
13
14
|
*/
|
|
14
15
|
size?: typeof sizes[number];
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The resize mode of the textarea. Can be `auto` or `manual`. Defaults to `auto`.
|
|
19
|
+
* When set to `auto`, the textarea will resize vertically as needed.
|
|
20
|
+
* When set to `manual`, the textarea will not resize automatically but can be resized by the user.
|
|
21
|
+
*/
|
|
22
|
+
resize?: typeof resizeModes[number];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The value of the textarea (used as a key/value pair in HTML forms with `name`).
|
|
26
|
+
*/
|
|
27
|
+
value: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The name of the textarea (used as a key/value pair with `value`). This is required in order to work properly with forms.
|
|
31
|
+
*/
|
|
32
|
+
name?: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Allows the user to enable or disable autocomplete functionality on the textarea field.
|
|
36
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) for more information and values.
|
|
37
|
+
*/
|
|
38
|
+
autocomplete?: string;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* If true, the textarea will be focused on the first render.
|
|
42
|
+
* No more than one element in the document or dialog may have the autofocus attribute. If applied to multiple elements the first one will receive focus.
|
|
43
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/autofocus) for more information.
|
|
44
|
+
*/
|
|
45
|
+
autoFocus?: boolean;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* When true, the user cannot edit the control. Not the same as disabled.
|
|
49
|
+
* See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly) for more information.
|
|
50
|
+
*/
|
|
51
|
+
readonly?: boolean;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* If true, the textarea is required to have a value before submitting the form. If there is no value, then the component validity state will be invalid.
|
|
55
|
+
*/
|
|
56
|
+
required?: boolean;
|
|
15
57
|
}
|
|
16
58
|
|
|
17
59
|
/**
|
|
18
60
|
* The default values for the `TextareaProps` that are required (i.e. they have a fallback value in the component).
|
|
19
61
|
*/
|
|
20
|
-
type DefaultProps = ComponentDefaultProps<TextareaProps
|
|
62
|
+
type DefaultProps = ComponentDefaultProps<TextareaProps, keyof Omit<TextareaProps, 'name'| 'autocomplete'>>;
|
|
21
63
|
|
|
22
64
|
/**
|
|
23
65
|
* Default values for optional properties that have default fallback values in the component.
|
|
@@ -25,4 +67,9 @@ type DefaultProps = ComponentDefaultProps<TextareaProps>;
|
|
|
25
67
|
export const defaultProps: DefaultProps = {
|
|
26
68
|
disabled: false,
|
|
27
69
|
size: 'medium',
|
|
70
|
+
resize: 'auto',
|
|
71
|
+
value: '',
|
|
72
|
+
autoFocus: false,
|
|
73
|
+
readonly: false,
|
|
74
|
+
required: false,
|
|
28
75
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
LitElement, html, unsafeCSS, PropertyValues,
|
|
3
|
+
} from 'lit';
|
|
4
|
+
import { property, query } from 'lit/decorators.js';
|
|
3
5
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
|
+
import { live } from 'lit/directives/live.js';
|
|
7
|
+
import throttle from 'lodash.throttle';
|
|
4
8
|
|
|
5
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
validPropertyValues, RtlMixin, defineCustomElement, FormControlMixin, wrapNativeEvent,
|
|
11
|
+
} from '@justeattakeaway/pie-webc-core';
|
|
6
12
|
|
|
7
13
|
import styles from './textarea.scss?inline';
|
|
8
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
TextareaProps, defaultProps, sizes, resizeModes,
|
|
16
|
+
} from './defs';
|
|
9
17
|
|
|
10
18
|
// Valid values available to consumers
|
|
11
19
|
export * from './defs';
|
|
@@ -14,31 +22,160 @@ const componentSelector = 'pie-textarea';
|
|
|
14
22
|
|
|
15
23
|
/**
|
|
16
24
|
* @tagname pie-textarea
|
|
25
|
+
* @event {InputEvent} input - when the textarea value is changed.
|
|
26
|
+
* @event {CustomEvent} change - when the textarea value is changed.
|
|
17
27
|
*/
|
|
18
|
-
export class PieTextarea extends RtlMixin(LitElement) implements TextareaProps {
|
|
28
|
+
export class PieTextarea extends FormControlMixin(RtlMixin(LitElement)) implements TextareaProps {
|
|
19
29
|
static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true };
|
|
20
30
|
|
|
31
|
+
@property({ type: String })
|
|
32
|
+
public value = defaultProps.value;
|
|
33
|
+
|
|
21
34
|
@property({ type: Boolean, reflect: true })
|
|
22
|
-
public disabled
|
|
35
|
+
public disabled = defaultProps.disabled;
|
|
23
36
|
|
|
24
37
|
@property({ type: String })
|
|
25
38
|
@validPropertyValues(componentSelector, sizes, defaultProps.size)
|
|
26
|
-
public size
|
|
39
|
+
public size = defaultProps.size;
|
|
40
|
+
|
|
41
|
+
@property({ type: String })
|
|
42
|
+
@validPropertyValues(componentSelector, resizeModes, defaultProps.resize)
|
|
43
|
+
public resize = defaultProps.resize;
|
|
44
|
+
|
|
45
|
+
@property({ type: Boolean })
|
|
46
|
+
public readonly = defaultProps.readonly;
|
|
47
|
+
|
|
48
|
+
@property({ type: Boolean })
|
|
49
|
+
public autoFocus = defaultProps.autoFocus;
|
|
50
|
+
|
|
51
|
+
@property({ type: Boolean })
|
|
52
|
+
public required = defaultProps.required;
|
|
53
|
+
|
|
54
|
+
@property({ type: String })
|
|
55
|
+
public name?: TextareaProps['name'];
|
|
56
|
+
|
|
57
|
+
@property({ type: String })
|
|
58
|
+
public autocomplete?: TextareaProps['autocomplete'];
|
|
59
|
+
|
|
60
|
+
@query('textarea')
|
|
61
|
+
private _textarea!: HTMLTextAreaElement;
|
|
62
|
+
|
|
63
|
+
private _throttledResize = throttle(() => {
|
|
64
|
+
if (this.resize === 'auto') {
|
|
65
|
+
this._textarea.style.height = 'auto';
|
|
66
|
+
this._textarea.style.height = `${this._textarea.scrollHeight + 2}px`; // +2 for border thicknesses
|
|
67
|
+
}
|
|
68
|
+
}, 100);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* (Read-only) returns a ValidityState with the validity states that this element is in.
|
|
72
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validity
|
|
73
|
+
*/
|
|
74
|
+
public get validity (): ValidityState {
|
|
75
|
+
return (this._textarea as HTMLTextAreaElement).validity;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Called after the disabled state of the element changes,
|
|
80
|
+
* either because the disabled attribute of this element was added or removed;
|
|
81
|
+
* or because the disabled state changed on a <fieldset> that's an ancestor of this element.
|
|
82
|
+
* @param disabled - The latest disabled state of the input.
|
|
83
|
+
*/
|
|
84
|
+
public formDisabledCallback (disabled: boolean): void {
|
|
85
|
+
this.disabled = disabled;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Called when the form that owns this component is reset.
|
|
90
|
+
* Resets the value to the default value.
|
|
91
|
+
*/
|
|
92
|
+
public formResetCallback (): void {
|
|
93
|
+
this.value = defaultProps.value;
|
|
94
|
+
|
|
95
|
+
this._internals.setFormValue(this.value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
protected firstUpdated (): void {
|
|
99
|
+
this._internals.setFormValue(this.value);
|
|
100
|
+
|
|
101
|
+
this._textarea.addEventListener('keydown', this.handleKeyDown);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private handleResize () {
|
|
105
|
+
this._throttledResize();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
protected updated (changedProperties: PropertyValues<this>) {
|
|
109
|
+
if (this.resize === 'auto' && (changedProperties.has('resize') || changedProperties.has('size'))) {
|
|
110
|
+
this.handleResize();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (changedProperties.has('value')) {
|
|
114
|
+
this._internals.setFormValue(this.value);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Handles data processing in response to the input event. The native input event is left to bubble up.
|
|
120
|
+
* @param event - The input event.
|
|
121
|
+
*/
|
|
122
|
+
private handleInput = (event: InputEvent) => {
|
|
123
|
+
this.value = (event.target as HTMLTextAreaElement).value;
|
|
124
|
+
this._internals.setFormValue(this.value);
|
|
125
|
+
|
|
126
|
+
this.handleResize();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
private handleChange = (event: Event) => {
|
|
130
|
+
// We have to create our own change event because the native one
|
|
131
|
+
// does not penetrate the shadow boundary.
|
|
132
|
+
|
|
133
|
+
// This is because some events set `composed` to `false`.
|
|
134
|
+
// Reference: https://javascript.info/shadow-dom-events#event-composed
|
|
135
|
+
const customChangeEvent = wrapNativeEvent(event);
|
|
136
|
+
this.dispatchEvent(customChangeEvent);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
private handleKeyDown = (event: KeyboardEvent) => {
|
|
140
|
+
if (event.key === 'Enter') {
|
|
141
|
+
event.stopPropagation();
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
public disconnectedCallback (): void {
|
|
146
|
+
this._textarea.removeEventListener('keydown', this.handleKeyDown);
|
|
147
|
+
}
|
|
27
148
|
|
|
28
149
|
render () {
|
|
29
150
|
const {
|
|
30
151
|
disabled,
|
|
152
|
+
resize,
|
|
31
153
|
size,
|
|
154
|
+
autocomplete,
|
|
155
|
+
autoFocus,
|
|
156
|
+
name,
|
|
157
|
+
readonly,
|
|
158
|
+
value,
|
|
159
|
+
required,
|
|
32
160
|
} = this;
|
|
33
161
|
|
|
34
162
|
return html`
|
|
35
163
|
<div
|
|
36
|
-
class="c-
|
|
37
|
-
data-test-id="pie-textarea-
|
|
38
|
-
data-pie-size
|
|
164
|
+
class="c-textareaWrapper"
|
|
165
|
+
data-test-id="pie-textarea-wrapper"
|
|
166
|
+
data-pie-size="${size}"
|
|
167
|
+
data-pie-resize="${resize}">
|
|
39
168
|
<textarea
|
|
40
|
-
|
|
169
|
+
name=${ifDefined(name)}
|
|
170
|
+
autocomplete=${ifDefined(autocomplete)}
|
|
171
|
+
.value=${live(value)}
|
|
172
|
+
?autofocus=${autoFocus}
|
|
173
|
+
?readonly=${readonly}
|
|
174
|
+
?required=${required}
|
|
41
175
|
?disabled=${disabled}
|
|
176
|
+
@input=${this.handleInput}
|
|
177
|
+
@change=${this.handleChange}
|
|
178
|
+
data-test-id="pie-textarea"
|
|
42
179
|
></textarea>
|
|
43
180
|
</div>`;
|
|
44
181
|
}
|
package/src/react.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { createComponent } from '@lit/react';
|
|
2
|
+
import { createComponent, EventName } from '@lit/react';
|
|
3
3
|
import { PieTextarea as PieTextareaLit } from './index';
|
|
4
4
|
import { TextareaProps } from './defs';
|
|
5
5
|
|
|
@@ -10,10 +10,18 @@ const PieTextareaReact = createComponent({
|
|
|
10
10
|
elementClass: PieTextareaLit,
|
|
11
11
|
react: React,
|
|
12
12
|
tagName: 'pie-textarea',
|
|
13
|
-
events: {
|
|
13
|
+
events: {
|
|
14
|
+
onInput: 'input' as EventName<InputEvent>, // when the textarea value is changed.
|
|
15
|
+
onChange: 'change' as EventName<CustomEvent>, // when the textarea value is changed.
|
|
16
|
+
},
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
type ReactBaseType = React.HTMLAttributes<HTMLTextAreaElement>
|
|
17
20
|
|
|
21
|
+
type PieTextareaEvents = {
|
|
22
|
+
onInput?: (event: InputEvent) => void;
|
|
23
|
+
onChange?: (event: CustomEvent) => void;
|
|
24
|
+
};
|
|
25
|
+
|
|
18
26
|
export const PieTextarea = PieTextareaReact as React.ForwardRefExoticComponent<React.PropsWithoutRef<TextareaProps>
|
|
19
|
-
& React.RefAttributes<PieTextareaLit> & ReactBaseType>;
|
|
27
|
+
& React.RefAttributes<PieTextareaLit> & PieTextareaEvents & ReactBaseType>;
|
package/src/textarea.scss
CHANGED
|
@@ -1,22 +1,89 @@
|
|
|
1
1
|
@use '@justeattakeaway/pie-css/scss' as p;
|
|
2
2
|
|
|
3
|
-
.
|
|
4
|
-
|
|
3
|
+
// Heights are being defined based on the line height of the text and the padding.
|
|
4
|
+
// Changing the `size` property affects the padding and therefore the height of the textarea.
|
|
5
|
+
// Default height is two lines of text.
|
|
6
|
+
// Minimum height in manual resize mode is one line of text.
|
|
7
|
+
// Maximum height in auto resize mode is six lines of text.
|
|
8
|
+
.c-textareaWrapper {
|
|
9
|
+
--textarea-line-height: #{p.line-height(--dt-font-body-l-line-height)};
|
|
10
|
+
--textarea-border-thickness: 1px;
|
|
11
|
+
--textarea-resize: none;
|
|
12
|
+
--textarea-padding-inline: var(--dt-spacing-d);
|
|
13
|
+
--textarea-padding-block: var(--dt-spacing-c);
|
|
14
|
+
--textarea-background-color: var(--dt-color-container-default);
|
|
15
|
+
--textarea-border-color: var(--dt-color-interactive-form);
|
|
16
|
+
--textarea-content-color: var(--dt-color-content-default);
|
|
5
17
|
|
|
6
|
-
height
|
|
18
|
+
// Default height is two lines of text
|
|
19
|
+
--textarea-height: calc((var(--textarea-line-height) * 2) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));
|
|
20
|
+
|
|
21
|
+
line-height: 0; // Remove once there is text outside the textarea
|
|
22
|
+
|
|
23
|
+
textarea {
|
|
24
|
+
@include p.font-size(--dt-font-body-l-size);
|
|
25
|
+
line-height: var(--textarea-line-height);
|
|
26
|
+
font-family: var(--dt-font-body-l-family);
|
|
27
|
+
resize: var(--textarea-resize);
|
|
28
|
+
border: var(--textarea-border-thickness) solid var(--textarea-border-color);
|
|
29
|
+
background-color: var(--textarea-background-color);
|
|
30
|
+
color: var(--textarea-content-color);
|
|
31
|
+
|
|
32
|
+
border-radius: var(--dt-radius-rounded-c);
|
|
33
|
+
block-size: var(--textarea-height);
|
|
34
|
+
max-block-size: var(--textarea-max-height);
|
|
35
|
+
min-block-size: var(--textarea-min-height);
|
|
36
|
+
|
|
37
|
+
padding-block-start: var(--textarea-padding-block);
|
|
38
|
+
padding-block-end: var(--textarea-padding-block);
|
|
39
|
+
padding-inline-start: var(--textarea-padding-inline);
|
|
40
|
+
padding-inline-end: var(--textarea-padding-inline);
|
|
41
|
+
|
|
42
|
+
&[disabled] {
|
|
43
|
+
--textarea-background-color: var(--dt-color-disabled-01);
|
|
44
|
+
--textarea-border-color: var(--dt-color-disabled-01);
|
|
45
|
+
--textarea-content-color: var(--dt-color-content-disabled);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@media (hover: hover) {
|
|
49
|
+
&:hover:not([disabled]) {
|
|
50
|
+
--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))));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
&:focus-visible {
|
|
55
|
+
@include p.focus;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
7
58
|
|
|
8
59
|
&[data-pie-size="large"] {
|
|
9
|
-
--textarea-
|
|
60
|
+
--textarea-padding-block: var(--dt-spacing-d);
|
|
10
61
|
}
|
|
11
62
|
|
|
12
63
|
&[data-pie-size="small"] {
|
|
13
|
-
--textarea-
|
|
64
|
+
--textarea-padding-block: var(--dt-spacing-b);
|
|
14
65
|
}
|
|
15
66
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
67
|
+
&[data-pie-resize="manual"] {
|
|
68
|
+
--textarea-resize: vertical;
|
|
69
|
+
|
|
70
|
+
// Minimum is one line of text
|
|
71
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 1) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2)); // One line of text
|
|
72
|
+
|
|
73
|
+
@media (pointer: coarse) {
|
|
74
|
+
// Fixed size for touch devices
|
|
75
|
+
--textarea-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));
|
|
76
|
+
--textarea-min-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));
|
|
77
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));
|
|
78
|
+
--textarea-resize: none;
|
|
79
|
+
}
|
|
19
80
|
}
|
|
20
|
-
}
|
|
21
81
|
|
|
82
|
+
&[data-pie-resize="auto"] {
|
|
83
|
+
// Maximum is six lines of text
|
|
84
|
+
--textarea-max-height: calc((var(--textarea-line-height) * 6) + (var(--textarea-padding-block) * 2) + (var(--textarea-border-thickness) * 2));
|
|
22
85
|
|
|
86
|
+
// Minimum is two lines of text
|
|
87
|
+
--textarea-min-height: var(--textarea-height);
|
|
88
|
+
}
|
|
89
|
+
}
|