@crowdstrike/glide-core 0.10.0 → 0.12.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/dist/checkbox-group.d.ts +3 -0
- package/dist/checkbox-group.js +43 -1
- package/dist/checkbox-group.styles.js +12 -0
- package/dist/checkbox-group.test.validity.js +69 -0
- package/dist/checkbox.d.ts +3 -1
- package/dist/checkbox.js +135 -1
- package/dist/checkbox.styles.js +12 -0
- package/dist/checkbox.test.events.js +9 -0
- package/dist/checkbox.test.validity.js +77 -1
- package/dist/dropdown.d.ts +3 -0
- package/dist/dropdown.js +195 -1
- package/dist/dropdown.option.d.ts +1 -0
- package/dist/dropdown.option.js +1 -1
- package/dist/dropdown.option.test.events.js +9 -1
- package/dist/dropdown.option.test.interactions.single.js +2 -2
- package/dist/dropdown.styles.js +18 -6
- package/dist/dropdown.test.basics.d.ts +1 -1
- package/dist/dropdown.test.basics.js +19 -1
- package/dist/dropdown.test.basics.multiple.js +2 -1
- package/dist/dropdown.test.events.filterable.js +13 -2
- package/dist/dropdown.test.events.single.js +19 -0
- package/dist/dropdown.test.form.multiple.js +3 -2
- package/dist/dropdown.test.interactions.filterable.js +20 -0
- package/dist/dropdown.test.interactions.js +20 -14
- package/dist/dropdown.test.interactions.multiple.js +24 -10
- package/dist/dropdown.test.interactions.single.js +32 -0
- package/dist/dropdown.test.validity.js +172 -1
- package/dist/input.d.ts +4 -0
- package/dist/input.js +155 -1
- package/dist/input.styles.js +8 -0
- package/dist/input.test.validity.js +140 -62
- package/dist/menu.d.ts +2 -0
- package/dist/menu.js +1 -1
- package/dist/menu.test.basics.d.ts +1 -1
- package/dist/menu.test.basics.js +12 -27
- package/dist/menu.test.interactions.js +90 -0
- package/dist/radio-group.d.ts +3 -0
- package/dist/radio-group.js +45 -1
- package/dist/radio-group.styles.js +12 -0
- package/dist/radio-group.test.validity.js +82 -0
- package/dist/styles/variables.css +1 -1
- package/dist/tab.group.d.ts +1 -0
- package/dist/tab.group.js +1 -1
- package/dist/tab.group.styles.js +6 -0
- package/dist/tag.d.ts +1 -2
- package/dist/tag.js +1 -1
- package/dist/tag.styles.js +12 -3
- package/dist/tag.test.basics.js +1 -0
- package/dist/tag.test.interactions.js +8 -6
- package/dist/textarea.d.ts +3 -0
- package/dist/textarea.js +58 -2
- package/dist/textarea.styles.js +8 -0
- package/dist/textarea.test.events.js +0 -114
- package/dist/textarea.test.validity.js +64 -72
- package/dist/tooltip.d.ts +2 -1
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.styles.js +2 -1
- package/dist/tree.item.menu.d.ts +1 -0
- package/dist/tree.item.menu.js +1 -1
- package/dist/tree.item.menu.test.basics.js +22 -1
- package/dist/tree.item.styles.js +3 -6
- package/package.json +1 -1
@@ -359,6 +359,22 @@ it('does not activate the next option on ArrowDown when a tag is focused', async
|
|
359
359
|
await sendKeys({ press: 'ArrowDown' });
|
360
360
|
expect(options[0]?.privateActive).to.be.true;
|
361
361
|
});
|
362
|
+
it('updates its tag when the `label` of a selected option is changed programmatically', async () => {
|
363
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
364
|
+
<glide-core-dropdown-option
|
365
|
+
label="One"
|
366
|
+
selected
|
367
|
+
></glide-core-dropdown-option>
|
368
|
+
|
369
|
+
<glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
|
370
|
+
</glide-core-dropdown>`);
|
371
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
372
|
+
assert(option);
|
373
|
+
option.label = 'Three';
|
374
|
+
await elementUpdated(component);
|
375
|
+
const tag = component.shadowRoot?.querySelector('[data-test="tag"]');
|
376
|
+
expect(tag?.label).to.equal('Three');
|
377
|
+
});
|
362
378
|
it('selects and deselects options when `value` is changed programmatically', async () => {
|
363
379
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
364
380
|
<glide-core-dropdown-option
|
@@ -444,14 +460,13 @@ it('updates `value` when a option is selected or deselected via Enter', async ()
|
|
444
460
|
</glide-core-dropdown>`);
|
445
461
|
// Wait for it to open.
|
446
462
|
await aTimeout(0);
|
447
|
-
|
448
|
-
|
463
|
+
component.focus();
|
464
|
+
await sendKeys({ press: 'ArrowDown' });
|
449
465
|
await sendKeys({ press: 'Enter' });
|
450
466
|
expect(component.value).to.deep.equal(['one', 'two']);
|
451
|
-
options[1].focus();
|
452
467
|
await sendKeys({ press: 'Enter' });
|
453
468
|
expect(component.value).to.deep.equal(['one']);
|
454
|
-
|
469
|
+
await sendKeys({ press: 'ArrowDown' });
|
455
470
|
await sendKeys({ press: 'Enter' });
|
456
471
|
expect(component.value).to.deep.equal(['one']);
|
457
472
|
});
|
@@ -472,14 +487,13 @@ it('updates `value` when an option is selected or deselected via Space', async (
|
|
472
487
|
</glide-core-dropdown>`);
|
473
488
|
// Wait for it to open.
|
474
489
|
await aTimeout(0);
|
475
|
-
|
476
|
-
|
490
|
+
component.focus();
|
491
|
+
await sendKeys({ press: 'ArrowDown' });
|
477
492
|
await sendKeys({ press: ' ' });
|
478
493
|
expect(component.value).to.deep.equal(['one', 'two']);
|
479
|
-
options[1].focus();
|
480
494
|
await sendKeys({ press: ' ' });
|
481
495
|
expect(component.value).to.deep.equal(['one']);
|
482
|
-
|
496
|
+
await sendKeys({ press: 'ArrowDown' });
|
483
497
|
await sendKeys({ press: ' ' });
|
484
498
|
expect(component.value).to.deep.equal(['one']);
|
485
499
|
});
|
@@ -1071,7 +1085,7 @@ it('does not set Select All as indeterminate when all options are selected', asy
|
|
1071
1085
|
const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
|
1072
1086
|
expect(selectAll?.privateIndeterminate).to.be.false;
|
1073
1087
|
});
|
1074
|
-
it('
|
1088
|
+
it('closes when a tag is clicked', async () => {
|
1075
1089
|
const component = await fixture(html `<glide-core-dropdown open multiple>
|
1076
1090
|
<glide-core-dropdown-option
|
1077
1091
|
label="One"
|
@@ -1095,7 +1109,7 @@ it('remains open when a tag is clicked', async () => {
|
|
1095
1109
|
position: [Math.ceil(x), Math.ceil(y)],
|
1096
1110
|
});
|
1097
1111
|
await elementUpdated(component);
|
1098
|
-
expect(component.open).to.be.
|
1112
|
+
expect(component.open).to.be.false;
|
1099
1113
|
});
|
1100
1114
|
it('cannot be tabbed to when `disabled`', async () => {
|
1101
1115
|
await fixture(html `<glide-core-dropdown
|
@@ -176,6 +176,8 @@ it('closes when an option is selected via click', async () => {
|
|
176
176
|
value="value"
|
177
177
|
></glide-core-dropdown-option>
|
178
178
|
</glide-core-dropdown>`);
|
179
|
+
// Wait for it to open.
|
180
|
+
await aTimeout(0);
|
179
181
|
component.querySelector('glide-core-dropdown-option')?.click();
|
180
182
|
expect(component.open).to.be.false;
|
181
183
|
});
|
@@ -186,6 +188,8 @@ it('closes when an option is selected via Space', async () => {
|
|
186
188
|
value="value"
|
187
189
|
></glide-core-dropdown-option>
|
188
190
|
</glide-core-dropdown>`);
|
191
|
+
// Wait for it to open.
|
192
|
+
await aTimeout(0);
|
189
193
|
component.focus();
|
190
194
|
await sendKeys({ press: ' ' });
|
191
195
|
expect(component.open).to.be.false;
|
@@ -197,6 +201,8 @@ it('closes when an option is selected via Enter', async () => {
|
|
197
201
|
value="value"
|
198
202
|
></glide-core-dropdown-option>
|
199
203
|
</glide-core-dropdown>`);
|
204
|
+
// Wait for it to open.
|
205
|
+
await aTimeout(0);
|
200
206
|
component.focus();
|
201
207
|
await sendKeys({ press: 'Enter' });
|
202
208
|
expect(component.open).to.be.false;
|
@@ -228,6 +234,18 @@ it('closes when an option is selected via Space', async () => {
|
|
228
234
|
await sendKeys({ press: ' ' });
|
229
235
|
expect(component.open).to.be.false;
|
230
236
|
});
|
237
|
+
it('closes when an already selected option is clicked', async () => {
|
238
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
239
|
+
<glide-core-dropdown-option
|
240
|
+
label="Label"
|
241
|
+
selected
|
242
|
+
></glide-core-dropdown-option>
|
243
|
+
</glide-core-dropdown>`);
|
244
|
+
// Wait for it to open.
|
245
|
+
await aTimeout(0);
|
246
|
+
component.querySelector('glide-core-dropdown-option')?.click();
|
247
|
+
expect(component.open).to.be.false;
|
248
|
+
});
|
231
249
|
it('deselects all other options when one is newly selected', async () => {
|
232
250
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
233
251
|
<glide-core-dropdown-option
|
@@ -255,6 +273,20 @@ it('deselects all other options when one is newly selected', async () => {
|
|
255
273
|
expect(options[1].selected).to.be.true;
|
256
274
|
expect(options[2].selected).to.be.false;
|
257
275
|
});
|
276
|
+
it('updates its internal label when the `label` of a selected option is changed programmatically', async () => {
|
277
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
278
|
+
<glide-core-dropdown-option
|
279
|
+
label="One"
|
280
|
+
selected
|
281
|
+
></glide-core-dropdown-option>
|
282
|
+
</glide-core-dropdown>`);
|
283
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
284
|
+
assert(option);
|
285
|
+
option.label = 'Two';
|
286
|
+
await elementUpdated(component);
|
287
|
+
const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
|
288
|
+
expect(label?.textContent?.trim()).to.equal(option?.label);
|
289
|
+
});
|
258
290
|
it('selects and deselects options when `value` is changed programmatically', async () => {
|
259
291
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
260
292
|
<glide-core-dropdown-option
|
@@ -1,6 +1,6 @@
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
2
|
import './dropdown.option.js';
|
3
|
-
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
|
4
4
|
import GlideCoreDropdown from './dropdown.js';
|
5
5
|
GlideCoreDropdown.shadowRootOptions.mode = 'open';
|
6
6
|
it('is valid if not required and no option is selected', async () => {
|
@@ -28,6 +28,23 @@ it('is invalid if required and no option is selected', async () => {
|
|
28
28
|
expect(component.checkValidity()).to.be.false;
|
29
29
|
expect(component.reportValidity()).to.be.false;
|
30
30
|
});
|
31
|
+
it('is invalid if required and no option is selected when `filterable`', async () => {
|
32
|
+
const component = await fixture(html `<glide-core-dropdown
|
33
|
+
label="Label"
|
34
|
+
placeholder="Placeholder"
|
35
|
+
filterable
|
36
|
+
required
|
37
|
+
>
|
38
|
+
<glide-core-dropdown-option
|
39
|
+
label="Label"
|
40
|
+
value="value"
|
41
|
+
></glide-core-dropdown-option>
|
42
|
+
</glide-core-dropdown>`);
|
43
|
+
expect(component.validity.valid).to.be.false;
|
44
|
+
expect(component.validity?.valueMissing).to.be.true;
|
45
|
+
expect(component.checkValidity()).to.be.false;
|
46
|
+
expect(component.reportValidity()).to.be.false;
|
47
|
+
});
|
31
48
|
it('is both invalid and valid if required but disabled and no option is selected', async () => {
|
32
49
|
const component = await fixture(html `<glide-core-dropdown
|
33
50
|
label="Label"
|
@@ -45,3 +62,157 @@ it('is both invalid and valid if required but disabled and no option is selected
|
|
45
62
|
expect(component.checkValidity()).to.be.true;
|
46
63
|
expect(component.reportValidity()).to.be.true;
|
47
64
|
});
|
65
|
+
it('sets the validity message with `setCustomValidity()`', async () => {
|
66
|
+
const component = await fixture(html `<glide-core-dropdown label="Label">
|
67
|
+
<glide-core-dropdown-option
|
68
|
+
label="Label"
|
69
|
+
value="value"
|
70
|
+
></glide-core-dropdown-option>
|
71
|
+
</glide-core-dropdown>`);
|
72
|
+
component.setCustomValidity('validity message');
|
73
|
+
expect(component.validity?.valid).to.be.false;
|
74
|
+
expect(component.validity?.customError).to.be.true;
|
75
|
+
expect(component.checkValidity()).to.be.false;
|
76
|
+
await elementUpdated(component);
|
77
|
+
// Like native, the validity message shouldn't display until `reportValidity()` is called.
|
78
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
79
|
+
?.textContent).to.be.undefined;
|
80
|
+
expect(component.reportValidity()).to.be.false;
|
81
|
+
await elementUpdated(component);
|
82
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
83
|
+
?.textContent).to.equal('validity message');
|
84
|
+
});
|
85
|
+
it('removes a validity message with an empty argument to `setCustomValidity()`', async () => {
|
86
|
+
const component = await fixture(html `<glide-core-dropdown label="Label">
|
87
|
+
<glide-core-dropdown-option
|
88
|
+
label="Label"
|
89
|
+
value="value"
|
90
|
+
></glide-core-dropdown-option>
|
91
|
+
</glide-core-dropdown>`);
|
92
|
+
component.setCustomValidity('validity message');
|
93
|
+
component.reportValidity();
|
94
|
+
await elementUpdated(component);
|
95
|
+
component.setCustomValidity('');
|
96
|
+
await elementUpdated(component);
|
97
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
98
|
+
?.textContent).to.be.undefined;
|
99
|
+
});
|
100
|
+
it('is invalid when `setValidity()` is called', async () => {
|
101
|
+
const component = await fixture(html `<glide-core-dropdown label="Label">
|
102
|
+
<glide-core-dropdown-option
|
103
|
+
label="Label"
|
104
|
+
value="value"
|
105
|
+
></glide-core-dropdown-option>
|
106
|
+
</glide-core-dropdown>`);
|
107
|
+
component.setValidity({ customError: true }, 'validity message');
|
108
|
+
expect(component.validity.valid).to.be.false;
|
109
|
+
await elementUpdated(component);
|
110
|
+
// Like native, the validity message shouldn't display until `reportValidity()` is called.
|
111
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
112
|
+
?.textContent).to.be.undefined;
|
113
|
+
expect(component.validity?.customError).to.be.true;
|
114
|
+
component.reportValidity();
|
115
|
+
await elementUpdated(component);
|
116
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
117
|
+
?.textContent).to.equal('validity message');
|
118
|
+
});
|
119
|
+
it('is valid when `setValidity()` is called', async () => {
|
120
|
+
const component = await fixture(html `<glide-core-dropdown label="Label">
|
121
|
+
<glide-core-dropdown-option
|
122
|
+
label="Label"
|
123
|
+
value="value"
|
124
|
+
></glide-core-dropdown-option>
|
125
|
+
</glide-core-dropdown>`);
|
126
|
+
component.setValidity({ customError: true }, 'validity message');
|
127
|
+
component.setValidity({});
|
128
|
+
await elementUpdated(component);
|
129
|
+
expect(component.validity.valid).to.be.true;
|
130
|
+
expect(component.validity.customError).to.be.false;
|
131
|
+
expect(component.reportValidity()).to.be.true;
|
132
|
+
await elementUpdated(component);
|
133
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
134
|
+
?.textContent).to.be.undefined;
|
135
|
+
});
|
136
|
+
it('sets the validity message with `setCustomValidity()` when `filterable`', async () => {
|
137
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" filterable>
|
138
|
+
<glide-core-dropdown-option
|
139
|
+
label="Label"
|
140
|
+
value="value"
|
141
|
+
></glide-core-dropdown-option>
|
142
|
+
</glide-core-dropdown>`);
|
143
|
+
component.setCustomValidity('validity message');
|
144
|
+
expect(component.validity?.valid).to.be.false;
|
145
|
+
expect(component.validity?.customError).to.be.true;
|
146
|
+
expect(component.checkValidity()).to.be.false;
|
147
|
+
await elementUpdated(component);
|
148
|
+
// Like native, the validity message shouldn't display until `reportValidity()` is called.
|
149
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
150
|
+
?.textContent).to.be.undefined;
|
151
|
+
expect(component.reportValidity()).to.be.false;
|
152
|
+
await elementUpdated(component);
|
153
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
154
|
+
?.textContent).to.equal('validity message');
|
155
|
+
});
|
156
|
+
it('removes a validity message with an empty argument to `setCustomValidity()` when `filterable`', async () => {
|
157
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" filterable>
|
158
|
+
<glide-core-dropdown-option
|
159
|
+
label="Label"
|
160
|
+
value="value"
|
161
|
+
></glide-core-dropdown-option>
|
162
|
+
</glide-core-dropdown>`);
|
163
|
+
component.setCustomValidity('validity message');
|
164
|
+
component.reportValidity();
|
165
|
+
await elementUpdated(component);
|
166
|
+
component.setCustomValidity('');
|
167
|
+
await elementUpdated(component);
|
168
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
169
|
+
?.textContent).to.be.undefined;
|
170
|
+
});
|
171
|
+
it('is invalid when `setValidity()` is called when `filterable`', async () => {
|
172
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" filterable>
|
173
|
+
<glide-core-dropdown-option
|
174
|
+
label="Label"
|
175
|
+
value="value"
|
176
|
+
></glide-core-dropdown-option>
|
177
|
+
</glide-core-dropdown>`);
|
178
|
+
component.setValidity({ customError: true }, 'validity message');
|
179
|
+
expect(component.validity.valid).to.be.false;
|
180
|
+
await elementUpdated(component);
|
181
|
+
// Like native, the validity message shouldn't display until `reportValidity()` is called.
|
182
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
183
|
+
?.textContent).to.be.undefined;
|
184
|
+
expect(component.validity?.customError).to.be.true;
|
185
|
+
component.reportValidity();
|
186
|
+
await elementUpdated(component);
|
187
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
188
|
+
?.textContent).to.equal('validity message');
|
189
|
+
});
|
190
|
+
it('is valid when `setValidity()` is called when `filterable`', async () => {
|
191
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" filterable>
|
192
|
+
<glide-core-dropdown-option
|
193
|
+
label="Label"
|
194
|
+
value="value"
|
195
|
+
></glide-core-dropdown-option>
|
196
|
+
</glide-core-dropdown>`);
|
197
|
+
component.setValidity({ customError: true }, 'validity message');
|
198
|
+
component.setValidity({});
|
199
|
+
await elementUpdated(component);
|
200
|
+
expect(component.validity.valid).to.be.true;
|
201
|
+
expect(component.validity.customError).to.be.false;
|
202
|
+
expect(component.reportValidity()).to.be.true;
|
203
|
+
await elementUpdated(component);
|
204
|
+
expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
|
205
|
+
?.textContent).to.be.undefined;
|
206
|
+
});
|
207
|
+
it('retains existing validity state when `setCustomValidity()` is called', async () => {
|
208
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" required>
|
209
|
+
<glide-core-dropdown-option
|
210
|
+
label="Label"
|
211
|
+
value="value"
|
212
|
+
></glide-core-dropdown-option>
|
213
|
+
</glide-core-dropdown>`);
|
214
|
+
component.setCustomValidity('validity message');
|
215
|
+
expect(component.validity?.valid).to.be.false;
|
216
|
+
expect(component.validity?.customError).to.be.true;
|
217
|
+
expect(component.validity?.valueMissing).to.be.true;
|
218
|
+
});
|
package/dist/input.d.ts
CHANGED
@@ -29,6 +29,7 @@ export default class GlideCoreInput extends LitElement {
|
|
29
29
|
label?: string;
|
30
30
|
hideLabel: boolean;
|
31
31
|
orientation: 'horizontal' | 'vertical';
|
32
|
+
pattern?: string;
|
32
33
|
placeholder?: string;
|
33
34
|
clearable: boolean;
|
34
35
|
spellcheck: boolean;
|
@@ -53,11 +54,14 @@ export default class GlideCoreInput extends LitElement {
|
|
53
54
|
get isClearIconVisible(): boolean;
|
54
55
|
render(): import("lit").TemplateResult<1>;
|
55
56
|
reportValidity(): boolean;
|
57
|
+
setCustomValidity(message: string): void;
|
58
|
+
setValidity(flags?: ValidityStateFlags, message?: string): void;
|
56
59
|
constructor();
|
57
60
|
private hasFocus;
|
58
61
|
private isBlurring;
|
59
62
|
private isCheckingValidity;
|
60
63
|
private isReportValidityOrSubmit;
|
61
64
|
private passwordVisible;
|
65
|
+
private validityMessage?;
|
62
66
|
}
|
63
67
|
export {};
|
package/dist/input.js
CHANGED
@@ -1 +1,155 @@
|
|
1
|
-
var __decorate=this&&this.__decorate||function(e,
|
1
|
+
var __decorate=this&&this.__decorate||function(t,e,i,s){var a,r=arguments.length,o=r<3?e:null===s?s=Object.getOwnPropertyDescriptor(e,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(t,e,i,s);else for(var l=t.length-1;l>=0;l--)(a=t[l])&&(o=(r<3?a(o):r>3?a(e,i,o):a(e,i))||o);return r>3&&o&&Object.defineProperty(e,i,o),o};import"./icon-button.js";import"./label.js";import{LitElement,html,nothing}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{unsafeHTML}from"lit/directives/unsafe-html.js";import{when}from"lit/directives/when.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import ow from"./library/ow.js";import styles from"./input.styles.js";export const SUPPORTED_TYPES=["email","number","password","search","tel","text","url"];let GlideCoreInput=class GlideCoreInput extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}get form(){return this.#t.form}get validity(){return this.pattern?(this.#t.setValidity({customError:Boolean(this.validityMessage),patternMismatch:!new RegExp(this.pattern).test(this.value),valueMissing:Boolean(this.required&&!this.value)}," ",this.#e.value),this.#t.validity):!this.pattern&&this.#t.validity.patternMismatch?(this.#t.setValidity({}),this.#t.validity):!this.required||this.value||this.disabled?this.required&&this.#t.validity.valueMissing&&this.value?(this.#t.setValidity({}),this.#t.validity):(this.required||!this.#t.validity.valueMissing||this.value||this.#t.setValidity({}),this.#t.validity):(this.#t.setValidity({customError:Boolean(this.validityMessage),valueMissing:!0}," ",this.#e.value),this.#t.validity)}get willValidate(){return this.#t.willValidate}blur(){this.#e.value?.blur()}checkValidity(){this.isCheckingValidity=!0;const t=this.#t.checkValidity();return this.isCheckingValidity=!1,t}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}get hasClearIcon(){return this.clearable&&!this.disabled&&!this.readonly}get isClearIconVisible(){return this.hasClearIcon&&this.value.length>0}render(){return html`
|
2
|
+
<glide-core-private-label
|
3
|
+
class=${classMap({left:"left"===this.privateSplit,middle:"middle"===this.privateSplit})}
|
4
|
+
orientation=${this.orientation}
|
5
|
+
split=${ifDefined(this.privateSplit??void 0)}
|
6
|
+
?disabled=${this.disabled}
|
7
|
+
?error=${this.#s||this.#a}
|
8
|
+
?hide=${this.hideLabel}
|
9
|
+
?required=${this.required}
|
10
|
+
>
|
11
|
+
<slot name="tooltip" slot="tooltip"></slot>
|
12
|
+
<label for="input"> ${this.label} </label>
|
13
|
+
|
14
|
+
<div
|
15
|
+
class=${classMap({"input-container":!0,focused:this.hasFocus,empty:""===this.value,disabled:this.disabled,readonly:this.readonly&&!this.disabled,error:this.#s||this.#a})}
|
16
|
+
slot="control"
|
17
|
+
>
|
18
|
+
<slot name="prefix-icon"></slot>
|
19
|
+
|
20
|
+
<input
|
21
|
+
aria-describedby="meta"
|
22
|
+
aria-invalid=${this.#s||this.#a}
|
23
|
+
id="input"
|
24
|
+
type=${"password"===this.type&&this.passwordVisible?"text":this.type}
|
25
|
+
.value=${this.value}
|
26
|
+
placeholder=${ifDefined(this.placeholder)}
|
27
|
+
autocapitalize=${this.autocapitalize}
|
28
|
+
autocomplete=${this.autocomplete}
|
29
|
+
spellcheck=${this.spellcheck}
|
30
|
+
?required=${this.required}
|
31
|
+
?readonly=${this.readonly}
|
32
|
+
?disabled=${this.disabled}
|
33
|
+
@focus=${this.#r}
|
34
|
+
@blur=${this.#o}
|
35
|
+
@change=${this.#l}
|
36
|
+
@input=${this.#n}
|
37
|
+
@keydown=${this.#d}
|
38
|
+
${ref(this.#e)}
|
39
|
+
/>
|
40
|
+
|
41
|
+
${this.hasClearIcon?html`
|
42
|
+
<glide-core-icon-button
|
43
|
+
variant="tertiary"
|
44
|
+
class=${classMap({"clear-icon-button":!0,"clear-icon-button--visible":this.isClearIconVisible})}
|
45
|
+
data-test="clear-button"
|
46
|
+
label=${this.#h.term("clearEntry",this.label)}
|
47
|
+
@click=${this.#p}
|
48
|
+
>
|
49
|
+
<!-- X icon -->
|
50
|
+
<svg
|
51
|
+
aria-hidden="true"
|
52
|
+
width="16"
|
53
|
+
height="16"
|
54
|
+
viewBox="0 0 24 24"
|
55
|
+
fill="none"
|
56
|
+
stroke="currentColor"
|
57
|
+
>
|
58
|
+
<path
|
59
|
+
d="M6 6L18 18"
|
60
|
+
stroke-width="2"
|
61
|
+
stroke-linecap="round"
|
62
|
+
stroke-linejoin="round"
|
63
|
+
/>
|
64
|
+
<path
|
65
|
+
d="M18 6L6 18"
|
66
|
+
stroke-width="2"
|
67
|
+
stroke-linecap="round"
|
68
|
+
stroke-linejoin="round"
|
69
|
+
/>
|
70
|
+
</svg>
|
71
|
+
</glide-core-icon-button>
|
72
|
+
`:nothing}
|
73
|
+
${"password"===this.type&&this.passwordToggle&&!this.disabled?html`
|
74
|
+
<glide-core-icon-button
|
75
|
+
variant="tertiary"
|
76
|
+
class="password-toggle"
|
77
|
+
data-test="password-toggle"
|
78
|
+
label=${this.passwordVisible?"Hide password":"Show password"}
|
79
|
+
aria-controls="input"
|
80
|
+
aria-expanded=${this.passwordVisible?"true":"false"}
|
81
|
+
@click=${this.#c}
|
82
|
+
>
|
83
|
+
${this.passwordVisible?html`<svg
|
84
|
+
aria-hidden="true"
|
85
|
+
width="16"
|
86
|
+
height="16"
|
87
|
+
fill="none"
|
88
|
+
viewBox="0 0 24 24"
|
89
|
+
stroke-width="1.5"
|
90
|
+
stroke="currentColor"
|
91
|
+
>
|
92
|
+
<path
|
93
|
+
stroke-linecap="round"
|
94
|
+
stroke-linejoin="round"
|
95
|
+
d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"
|
96
|
+
/>
|
97
|
+
</svg> `:html`<svg
|
98
|
+
aria-hidden="true"
|
99
|
+
width="16"
|
100
|
+
height="16"
|
101
|
+
fill="none"
|
102
|
+
viewBox="0 0 24 24"
|
103
|
+
stroke-width="1.5"
|
104
|
+
stroke="currentColor"
|
105
|
+
>
|
106
|
+
<path
|
107
|
+
stroke-linecap="round"
|
108
|
+
stroke-linejoin="round"
|
109
|
+
d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"
|
110
|
+
/>
|
111
|
+
<path
|
112
|
+
stroke-linecap="round"
|
113
|
+
stroke-linejoin="round"
|
114
|
+
d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"
|
115
|
+
/>
|
116
|
+
</svg>`}
|
117
|
+
</glide-core-icon-button>
|
118
|
+
`:nothing}
|
119
|
+
|
120
|
+
<div class="suffix-icon">
|
121
|
+
${"search"===this.type?magnifyingGlassIcon:html`<slot name="suffix-icon"></slot>`}
|
122
|
+
</div>
|
123
|
+
</div>
|
124
|
+
|
125
|
+
<div class="meta" id="meta" slot="description">
|
126
|
+
<slot
|
127
|
+
class=${classMap({description:!0,hidden:Boolean(this.#s&&this.validityMessage)})}
|
128
|
+
name="description"
|
129
|
+
></slot>
|
130
|
+
|
131
|
+
${when(this.#s&&this.validityMessage,(()=>html`<span class="validity-message" data-test="validity-message"
|
132
|
+
>${unsafeHTML(this.validityMessage)}</span
|
133
|
+
>`))}
|
134
|
+
${this.maxlength?html`
|
135
|
+
<div
|
136
|
+
class=${classMap({"character-count":!0,error:this.#a})}
|
137
|
+
data-test="character-count-container"
|
138
|
+
>
|
139
|
+
<!--
|
140
|
+
"aria-hidden" is used here so that the character counter
|
141
|
+
is not read aloud to screenreaders twice as we have a
|
142
|
+
more accesible, verbose description below.
|
143
|
+
-->
|
144
|
+
<span aria-hidden="true" data-test="character-count-text">
|
145
|
+
${this.#h.term("displayedCharacterCount",this.#u,this.maxlength)}
|
146
|
+
</span>
|
147
|
+
|
148
|
+
<span class="hidden" data-test="character-count-announcement"
|
149
|
+
>${this.#h.term("announcedCharacterCount",this.#u,this.maxlength)}</span
|
150
|
+
>
|
151
|
+
</div>
|
152
|
+
`:nothing}
|
153
|
+
</div>
|
154
|
+
</glide-core-private-label>
|
155
|
+
`}reportValidity(){this.isReportValidityOrSubmit=!0;const t=this.#t.reportValidity();return this.requestUpdate(),t}setCustomValidity(t){this.validityMessage=t,""===t?this.#t.setValidity({customError:!1},"",this.#e.value):this.#t.setValidity({customError:!0,patternMismatch:this.#t.validity.patternMismatch,valueMissing:this.#t.validity.valueMissing}," ",this.#e.value)}setValidity(t,e){this.validityMessage=e,this.#t.setValidity(t," ",this.#e.value)}constructor(){super(),this.type="text",this.name="",this.value="",this.hideLabel=!1,this.orientation="horizontal",this.clearable=!1,this.spellcheck=!1,this.autocapitalize="on",this.autocomplete="on",this.passwordToggle=!1,this.required=!1,this.readonly=!1,this.disabled=!1,this.hasFocus=!1,this.isBlurring=!1,this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.passwordVisible=!1,this.#e=createRef(),this.#h=new LocalizeController(this),this.#i=({formData:t})=>{this.name&&this.value&&!this.disabled&&t.append(this.name,this.value)},this.#t=this.attachInternals(),this.addEventListener("invalid",(t=>{if(t?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}))}#e;#t;#h;get#u(){return this.value.length}#i;get#a(){return Boolean(!this.disabled&&!this.readonly&&this.maxlength&&this.#u>this.maxlength)}get#s(){return!this.disabled&&!this.validity?.valid&&this.isReportValidityOrSubmit}#o(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1,this.hasFocus=!1}#l(t){ow(this.#e.value,ow.object.instanceOf(HTMLInputElement)),this.value=this.#e.value?.value,this.dispatchEvent(new Event(t.type,t))}#p(t){this.value="",this.dispatchEvent(new Event("clear",{bubbles:!0})),this.#e.value?.focus(),t.stopPropagation()}#r(){this.hasFocus=!0}#n(){ow(this.#e.value,ow.object.instanceOf(HTMLInputElement)),this.value=this.#e.value.value}#d(t){"Enter"===t.key&&this.form?.requestSubmit()}#c(){this.passwordVisible=!this.passwordVisible}};__decorate([property()],GlideCoreInput.prototype,"type",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"name",void 0),__decorate([property()],GlideCoreInput.prototype,"value",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreInput.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"orientation",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"pattern",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"placeholder",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"clearable",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"spellcheck",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"autocapitalize",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"autocomplete",void 0),__decorate([property({attribute:"password-toggle",type:Boolean})],GlideCoreInput.prototype,"passwordToggle",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"readonly",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"disabled",void 0),__decorate([property()],GlideCoreInput.prototype,"privateSplit",void 0),__decorate([property({type:Number,converter:t=>t&&Number.parseInt(t,10),reflect:!0})],GlideCoreInput.prototype,"maxlength",void 0),__decorate([state()],GlideCoreInput.prototype,"hasFocus",void 0),__decorate([state()],GlideCoreInput.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreInput.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreInput.prototype,"isReportValidityOrSubmit",void 0),__decorate([state()],GlideCoreInput.prototype,"passwordVisible",void 0),__decorate([state()],GlideCoreInput.prototype,"validityMessage",void 0),GlideCoreInput=__decorate([customElement("glide-core-input")],GlideCoreInput);export default GlideCoreInput;
|
package/dist/input.styles.js
CHANGED