@crowdstrike/glide-core 0.9.1 → 0.9.3

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.
Files changed (130) hide show
  1. package/dist/accordion.stories.d.ts +2 -4
  2. package/dist/accordion.styles.js +2 -4
  3. package/dist/button-group.button.styles.js +3 -8
  4. package/dist/button-group.stories.d.ts +2 -6
  5. package/dist/button-group.styles.js +2 -2
  6. package/dist/button.d.ts +12 -1
  7. package/dist/button.js +1 -1
  8. package/dist/button.stories.d.ts +2 -12
  9. package/dist/button.styles.js +2 -4
  10. package/dist/button.test.basics.js +47 -165
  11. package/dist/button.test.events.js +86 -10
  12. package/dist/checkbox-group.stories.d.ts +2 -3
  13. package/dist/checkbox.js +1 -1
  14. package/dist/checkbox.stories.d.ts +2 -6
  15. package/dist/checkbox.styles.js +43 -6
  16. package/dist/checkbox.test.form.js +16 -0
  17. package/dist/checkbox.test.interactions.js +8 -0
  18. package/dist/drawer.js +1 -1
  19. package/dist/drawer.stories.d.ts +1 -1
  20. package/dist/dropdown.d.ts +4 -2
  21. package/dist/dropdown.js +1 -1
  22. package/dist/dropdown.option.js +1 -1
  23. package/dist/dropdown.option.styles.js +2 -0
  24. package/dist/dropdown.stories.d.ts +4 -10
  25. package/dist/dropdown.styles.js +47 -29
  26. package/dist/dropdown.test.focus.filterable.js +20 -0
  27. package/dist/dropdown.test.focus.js +1 -0
  28. package/dist/dropdown.test.form.js +23 -112
  29. package/dist/dropdown.test.interactions.filterable.js +121 -17
  30. package/dist/dropdown.test.interactions.multiple.js +15 -22
  31. package/dist/dropdown.test.interactions.single.js +44 -22
  32. package/dist/form-controls-layout.stories.d.ts +1 -1
  33. package/dist/icon-button.d.ts +1 -1
  34. package/dist/icon-button.stories.d.ts +1 -3
  35. package/dist/icon-button.styles.js +2 -4
  36. package/dist/icons/checked.d.ts +5 -0
  37. package/dist/icons/checked.js +1 -1
  38. package/dist/input.d.ts +1 -1
  39. package/dist/input.js +1 -1
  40. package/dist/input.stories.d.ts +2 -13
  41. package/dist/input.styles.d.ts +1 -1
  42. package/dist/input.styles.js +93 -93
  43. package/dist/input.test.basics.js +45 -45
  44. package/dist/input.test.form.js +17 -0
  45. package/dist/label.styles.js +6 -11
  46. package/dist/library/localize.test.js +45 -0
  47. package/dist/menu.button.styles.js +1 -0
  48. package/dist/menu.js +1 -1
  49. package/dist/menu.link.styles.js +1 -0
  50. package/dist/menu.stories.d.ts +1 -1
  51. package/dist/menu.styles.js +3 -1
  52. package/dist/menu.test.events.js +1 -97
  53. package/dist/menu.test.focus.js +26 -3
  54. package/dist/menu.test.interactions.js +3 -0
  55. package/dist/modal.d.ts +0 -7
  56. package/dist/modal.icon-button.test.basics.js +9 -9
  57. package/dist/modal.stories.d.ts +3 -5
  58. package/dist/modal.styles.js +2 -4
  59. package/dist/modal.tertiary-icon.test.basics.js +14 -14
  60. package/dist/modal.test.accessibility.js +16 -27
  61. package/dist/modal.test.basics.js +64 -68
  62. package/dist/modal.test.close.js +12 -16
  63. package/dist/modal.test.events.js +32 -44
  64. package/dist/modal.test.lock-scroll.js +15 -25
  65. package/dist/modal.test.methods.js +8 -12
  66. package/dist/modal.test.scrollbars.js +2 -4
  67. package/dist/radio-group.js +1 -1
  68. package/dist/radio-group.stories.d.ts +2 -3
  69. package/dist/radio-group.test.basics.js +3 -3
  70. package/dist/radio-group.test.events.js +6 -6
  71. package/dist/radio-group.test.form.js +19 -0
  72. package/dist/radio.styles.js +2 -6
  73. package/dist/split-button.stories.d.ts +3 -8
  74. package/dist/split-button.styles.js +2 -4
  75. package/dist/split-container.styles.js +2 -4
  76. package/dist/status-indicator.stories.d.ts +1 -13
  77. package/dist/styles/focus-outline.d.ts +1 -1
  78. package/dist/styles/focus-outline.js +7 -1
  79. package/dist/styles/opacity-and-scale-animation.d.ts +2 -0
  80. package/dist/styles/opacity-and-scale-animation.js +24 -0
  81. package/dist/styles/variables.css +1 -1
  82. package/dist/styles/visually-hidden.d.ts +1 -1
  83. package/dist/styles/visually-hidden.js +14 -1
  84. package/dist/tab.group.d.ts +6 -6
  85. package/dist/tab.group.js +1 -1
  86. package/dist/tab.group.styles.js +46 -5
  87. package/dist/tab.group.test.basics.js +9 -2
  88. package/dist/tab.group.test.interactions.js +70 -93
  89. package/dist/tab.js +1 -1
  90. package/dist/tab.panel.styles.js +3 -9
  91. package/dist/tab.styles.js +6 -13
  92. package/dist/tab.test.basics.js +15 -17
  93. package/dist/tabs.stories.d.ts +2 -2
  94. package/dist/tag.js +1 -1
  95. package/dist/tag.stories.d.ts +2 -4
  96. package/dist/tag.styles.js +2 -4
  97. package/dist/tag.test.basics.js +28 -27
  98. package/dist/tag.test.events.js +3 -3
  99. package/dist/tag.test.focus.js +4 -4
  100. package/dist/textarea.d.ts +1 -1
  101. package/dist/textarea.stories.d.ts +1 -8
  102. package/dist/textarea.styles.d.ts +1 -1
  103. package/dist/textarea.styles.js +63 -67
  104. package/dist/textarea.test.basics.js +52 -52
  105. package/dist/toasts.d.ts +5 -0
  106. package/dist/toasts.stories.d.ts +1 -1
  107. package/dist/toasts.styles.js +1 -1
  108. package/dist/toggle.stories.d.ts +1 -4
  109. package/dist/toggle.styles.js +2 -1
  110. package/dist/toggle.test.interactions.js +11 -0
  111. package/dist/tooltip.js +1 -1
  112. package/dist/tooltip.styles.js +16 -30
  113. package/dist/tooltip.test.interactions.js +6 -6
  114. package/dist/translations/en.js +1 -1
  115. package/dist/translations/fr.d.ts +3 -1
  116. package/dist/translations/fr.js +1 -1
  117. package/dist/translations/ja.d.ts +3 -1
  118. package/dist/translations/ja.js +1 -1
  119. package/dist/tree.item.styles.js +11 -3
  120. package/dist/tree.item.test.basics.js +0 -30
  121. package/dist/tree.stories.d.ts +0 -9
  122. package/package.json +1 -3
  123. package/dist/button.test.form.d.ts +0 -1
  124. package/dist/button.test.form.js +0 -50
  125. package/dist/input.test.translations.js +0 -38
  126. package/dist/tag.test.translations.d.ts +0 -1
  127. package/dist/tag.test.translations.js +0 -25
  128. package/dist/textarea.test.translations.d.ts +0 -1
  129. package/dist/textarea.test.translations.js +0 -34
  130. /package/dist/{input.test.translations.d.ts → library/localize.test.d.ts} +0 -0
@@ -1,17 +1,16 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
2
  import './dropdown.option.js';
3
- import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
3
+ import { expect, fixture, html } from '@open-wc/testing';
4
+ import { sendKeys } from '@web/test-runner-commands';
4
5
  import GlideCoreDropdown from './dropdown.js';
5
6
  import GlideCoreDropdownOption from './dropdown.option.js';
7
+ import sinon from 'sinon';
6
8
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
7
9
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
8
10
  it('exposes standard form control properties and methods', async () => {
9
11
  const form = document.createElement('form');
10
12
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
11
- <glide-core-dropdown-option
12
- label="Label"
13
- value="value"
14
- ></glide-core-dropdown-option>
13
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
15
14
  </glide-core-dropdown>`, { parentNode: form });
16
15
  expect(component.form).to.equal(form);
17
16
  expect(component.validity instanceof ValidityState).to.be.true;
@@ -19,123 +18,35 @@ it('exposes standard form control properties and methods', async () => {
19
18
  expect(component.checkValidity).to.be.a('function');
20
19
  expect(component.reportValidity).to.be.a('function');
21
20
  });
22
- it('can be reset', async () => {
21
+ it('submits its form on Enter when closed', async () => {
23
22
  const form = document.createElement('form');
24
23
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
25
- <glide-core-dropdown-option
26
- label="One"
27
- value="one"
28
- ></glide-core-dropdown-option>
29
-
30
- <glide-core-dropdown-option
31
- label="Two"
32
- value="two"
33
- ></glide-core-dropdown-option>
24
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
34
25
  </glide-core-dropdown>`, {
35
26
  parentNode: form,
36
27
  });
37
- component
38
- .querySelector('glide-core-dropdown-option')
39
- ?.shadowRoot?.querySelector('[data-test="component"]')
40
- ?.dispatchEvent(new Event('click'));
41
- form.reset();
42
- await elementUpdated(component);
43
- const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
44
- expect(label?.textContent?.trim()).to.equal('Placeholder');
45
- expect(component.value).to.deep.equal([]);
46
- });
47
- it('can be reset to the initially selected option', async () => {
48
- const form = document.createElement('form');
49
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
50
- <glide-core-dropdown-option
51
- label="One"
52
- value="one"
53
- ></glide-core-dropdown-option>
54
-
55
- <glide-core-dropdown-option
56
- label="Two"
57
- value="two"
58
- selected
59
- ></glide-core-dropdown-option>
60
- </glide-core-dropdown>`, {
61
- parentNode: form,
62
- });
63
- component
64
- .querySelector('glide-core-dropdown-option')
65
- ?.shadowRoot?.querySelector('[data-test="component"]')
66
- ?.dispatchEvent(new Event('click'));
67
- form.reset();
68
- expect(component.value).to.deep.equal(['two']);
69
- });
70
- it('has `formData` value when an option is selected', async () => {
71
- const form = document.createElement('form');
72
- await fixture(html `<glide-core-dropdown
73
- label="Label"
74
- placeholder="Placeholder"
75
- name="name"
76
- >
77
- <glide-core-dropdown-option
78
- label="Label"
79
- value="value"
80
- selected
81
- ></glide-core-dropdown-option>
82
- </glide-core-dropdown>
83
- >`, {
84
- parentNode: form,
28
+ const spy = sinon.spy();
29
+ form.addEventListener('submit', (event) => {
30
+ event.preventDefault();
31
+ spy();
85
32
  });
86
- const formData = new FormData(form);
87
- expect(formData.get('name')).to.be.equal('["value"]');
33
+ component.focus();
34
+ await sendKeys({ press: 'Enter' });
35
+ expect(spy.callCount).to.equal(1);
88
36
  });
89
- it('has no `formData` value when no option is selected', async () => {
37
+ it('does not submit its form on Enter when open', async () => {
90
38
  const form = document.createElement('form');
91
- await fixture(html `<glide-core-dropdown
92
- label="Label"
93
- placeholder="Placeholder"
94
- name="name"
95
- >
96
- <glide-core-dropdown-option
97
- label=""
98
- value="value"
99
- ></glide-core-dropdown-option>
39
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
40
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
100
41
  </glide-core-dropdown>`, {
101
42
  parentNode: form,
102
43
  });
103
- const formData = new FormData(form);
104
- expect(formData.get('name')).to.be.null;
105
- });
106
- it('has no `formData` value when disabled and an option is selected', async () => {
107
- const form = document.createElement('form');
108
- await fixture(html `<glide-core-dropdown
109
- label="Label"
110
- placeholder="Placeholder"
111
- name="name"
112
- disabled
113
- >
114
- <glide-core-dropdown-option
115
- label="Label"
116
- value="value"
117
- selected
118
- ></glide-core-dropdown-option>
119
- </glide-core-dropdown>`, {
120
- parentNode: form,
121
- });
122
- const formData = new FormData(form);
123
- expect(formData.get('name')).to.be.null;
124
- });
125
- it('has no `formData` value when an option is selected that has no `value`', async () => {
126
- const form = document.createElement('form');
127
- await fixture(html `<glide-core-dropdown
128
- label="Label"
129
- placeholder="Placeholder"
130
- name="name"
131
- >
132
- <glide-core-dropdown-option
133
- label="Label"
134
- selected
135
- ></glide-core-dropdown-option>
136
- </glide-core-dropdown>`, {
137
- parentNode: form,
44
+ const spy = sinon.spy();
45
+ form.addEventListener('submit', (event) => {
46
+ event.preventDefault();
47
+ spy();
138
48
  });
139
- const formData = new FormData(form);
140
- expect(formData.get('name')).to.be.null;
49
+ component.focus();
50
+ await sendKeys({ press: 'Enter' });
51
+ expect(spy.callCount).to.equal(0);
141
52
  });
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
- import { aTimeout, assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
2
+ import { aTimeout, assert, elementUpdated, expect, fixture, html, oneEvent, } from '@open-wc/testing';
3
3
  import { sendKeys } from '@web/test-runner-commands';
4
4
  import GlideCoreDropdown from './dropdown.js';
5
5
  import GlideCoreDropdownOption from './dropdown.option.js';
@@ -97,15 +97,12 @@ it('unfilters when an option is selected via click', async () => {
97
97
  await aTimeout(0);
98
98
  component.focus();
99
99
  await sendKeys({ type: ' one ' });
100
- const option = [
101
- ...component.querySelectorAll('glide-core-dropdown-option'),
102
- ].find(({ hidden }) => !hidden);
103
- option?.click();
104
- const input = component.shadowRoot?.querySelector('[data-test="input"]');
100
+ [...component.querySelectorAll('glide-core-dropdown-option')]
101
+ .find(({ hidden }) => !hidden)
102
+ ?.click();
105
103
  const options = [
106
104
  ...component.querySelectorAll('glide-core-dropdown-option'),
107
105
  ].filter(({ hidden }) => !hidden);
108
- expect(input?.value).to.equal('');
109
106
  expect(options.length).to.equal(11);
110
107
  });
111
108
  it('unfilters when an option is selected via Enter', async () => {
@@ -115,11 +112,9 @@ it('unfilters when an option is selected via Enter', async () => {
115
112
  component.focus();
116
113
  await sendKeys({ type: ' one ' });
117
114
  await sendKeys({ press: 'Enter' });
118
- const input = component.shadowRoot?.querySelector('[data-test="input"]');
119
115
  const options = [
120
116
  ...component.querySelectorAll('glide-core-dropdown-option'),
121
117
  ].filter(({ hidden }) => !hidden);
122
- expect(input?.value).to.equal('');
123
118
  expect(options.length).to.equal(11);
124
119
  });
125
120
  it('shows the magnifying glass icon when there is a filter term', async () => {
@@ -154,6 +149,22 @@ it('hides the magnifying glass icon when an option is selected', async () => {
154
149
  await elementUpdated(component);
155
150
  expect(icon?.checkVisibility()).to.be.not.ok;
156
151
  });
152
+ it('hides the magnifying glass icon when closed programmatically and an option is selected', async () => {
153
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
154
+ ${defaultSlot}
155
+ </glide-core-dropdown>`);
156
+ // Wait for it to open.
157
+ await aTimeout(0);
158
+ const option = component.querySelector('glide-core-dropdown-option');
159
+ assert(option);
160
+ option.selected = true;
161
+ component.focus();
162
+ await sendKeys({ type: 'two' });
163
+ const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
164
+ component.open = false;
165
+ await elementUpdated(component);
166
+ expect(icon?.checkVisibility()).to.be.not.ok;
167
+ });
157
168
  it('does not filter on only whitespace', async () => {
158
169
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
159
170
  ${defaultSlot}
@@ -234,31 +245,53 @@ it('does not select options on Space', async () => {
234
245
  await sendKeys({ press: ' ' });
235
246
  expect(options[0]?.selected).to.be.false;
236
247
  });
237
- it('deselects options on Backspace', async () => {
248
+ it('deselects the last selected option on Backspace', async () => {
238
249
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
239
250
  ${defaultSlot}
240
251
  </glide-core-dropdown>`);
241
252
  const options = component.querySelectorAll('glide-core-dropdown-option');
242
253
  options[0].selected = true;
243
254
  options[1].selected = true;
255
+ await elementUpdated(component);
244
256
  component.focus();
257
+ component.shadowRoot
258
+ ?.querySelector('[data-test="input"]')
259
+ ?.setSelectionRange(0, 0);
260
+ await aTimeout(0);
245
261
  await sendKeys({ press: 'Backspace' });
246
262
  expect(options[1].selected).to.be.false;
247
263
  expect(options[0].selected).to.be.true;
248
264
  await sendKeys({ press: 'Backspace' });
249
265
  expect(options[0].selected).to.be.false;
250
266
  });
251
- it('uses the label of the selected option as a placeholder when not `multiple`', async () => {
267
+ it('deselects all options on Meta + Backspace', async () => {
268
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
269
+ ${defaultSlot}
270
+ </glide-core-dropdown>`);
271
+ const options = component.querySelectorAll('glide-core-dropdown-option');
272
+ options[0].selected = true;
273
+ options[1].selected = true;
274
+ await elementUpdated(component);
275
+ component.focus();
276
+ component.shadowRoot
277
+ ?.querySelector('[data-test="input"]')
278
+ ?.setSelectionRange(0, 0);
279
+ await sendKeys({ down: 'Meta' });
280
+ await sendKeys({ press: 'Backspace' });
281
+ await sendKeys({ up: 'Meta' });
282
+ expect(options[1].selected).to.be.false;
283
+ expect(options[0].selected).to.be.false;
284
+ });
285
+ it('set the `value` of the `<input>` to the label of the selected option when not `multiple`', async () => {
252
286
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
253
287
  ${defaultSlot}
254
288
  </glide-core-dropdown>`);
255
289
  const option = component?.querySelector('glide-core-dropdown-option');
256
290
  option?.click();
257
- await elementUpdated(component);
258
291
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
259
- expect(input?.placeholder).to.equal(option?.label);
292
+ expect(input?.value).to.equal(option?.label);
260
293
  });
261
- it('uses `placeholder` as a placeholder when `multiple` and an option is selected', async () => {
294
+ it('uses `placeholder` as a placeholder when `multiple` and no option is selected', async () => {
262
295
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
263
296
  ${defaultSlot}
264
297
  </glide-core-dropdown>`);
@@ -286,10 +319,10 @@ it('sets `aria-activedescendant` on ArrowDown', async () => {
286
319
  </glide-core-dropdown>`);
287
320
  // Wait for it to open.
288
321
  await aTimeout(0);
289
- const options = component.querySelectorAll('glide-core-dropdown-option');
290
- options[0]?.focus();
322
+ component.focus();
291
323
  await sendKeys({ press: 'ArrowDown' });
292
324
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
325
+ const options = component.querySelectorAll('glide-core-dropdown-option');
293
326
  expect(input?.getAttribute('aria-activedescendant')).to.equal(options[1].id);
294
327
  });
295
328
  it('sets `aria-activedescendant` on ArrowUp', async () => {
@@ -502,6 +535,77 @@ it('cannot be tabbed to when `disabled`', async () => {
502
535
  >
503
536
  ${defaultSlot}
504
537
  </glide-core-dropdown>`);
505
- await sendKeys({ down: 'Tab' });
538
+ await sendKeys({ press: 'Tab' });
506
539
  expect(document.activeElement).to.equal(document.body);
507
540
  });
541
+ it('sets the `value` of the `<input>` back to the label of selected option when something else is clicked', async () => {
542
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
543
+ ${defaultSlot}
544
+ </glide-core-dropdown>`);
545
+ // Wait for it to open.
546
+ await aTimeout(0);
547
+ const option = component.querySelector('glide-core-dropdown-option');
548
+ assert(option);
549
+ option.selected = true;
550
+ // Now type something other than "One" so we can check that it's reverted
551
+ // back to "One" when something else is clicked.
552
+ component.focus();
553
+ await sendKeys({ type: 'o' });
554
+ document.body.click();
555
+ const input = component.shadowRoot?.querySelector('[data-test="input"]');
556
+ expect(input?.value).to.equal('One');
557
+ });
558
+ it('selects the filter text when `click()` is called', async () => {
559
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
560
+ ${defaultSlot}
561
+ </glide-core-dropdown>`);
562
+ component.focus();
563
+ await sendKeys({ type: 'one' });
564
+ component.click();
565
+ expect(window.getSelection()?.toString()).to.equal('one');
566
+ });
567
+ it('selects the filter text when the `<input>` is clicked', async () => {
568
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
569
+ ${defaultSlot}
570
+ </glide-core-dropdown>`);
571
+ component.focus();
572
+ await sendKeys({ type: 'one' });
573
+ // Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
574
+ // which puts us in a guard in the event handler. `Event` has no `detail` property
575
+ // and would work. `CustomEvent` is used for completeness and to get us as close as
576
+ // possible to a real click. See the comment in the handler for more information.
577
+ component.shadowRoot
578
+ ?.querySelector('[data-test="input"]')
579
+ ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
580
+ expect(window.getSelection()?.toString()).to.equal('one');
581
+ });
582
+ it('selects the filter text when closed and the button is clicked', async () => {
583
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
584
+ ${defaultSlot}
585
+ </glide-core-dropdown>`);
586
+ component.focus();
587
+ await sendKeys({ type: 'one' });
588
+ component.open = false;
589
+ await elementUpdated(component);
590
+ // Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
591
+ // which puts us in a guard in the event handler. `Event` has no `detail` property
592
+ // and would work. `CustomEvent` is used for completeness and to get us as close as
593
+ // possible to a real click. See the comment in the handler for more information.
594
+ component.shadowRoot
595
+ ?.querySelector('[data-test="button"]')
596
+ ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
597
+ await elementUpdated(component);
598
+ expect(window.getSelection()?.toString()).to.equal('one');
599
+ });
600
+ it('clicks the `<input>` when `click()` is called', async () => {
601
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
602
+ ${defaultSlot}
603
+ </glide-core-dropdown>`);
604
+ const button = component.shadowRoot?.querySelector('[data-test="input"]');
605
+ assert(button);
606
+ setTimeout(() => {
607
+ component.click();
608
+ });
609
+ const event = await oneEvent(button, 'click');
610
+ expect(event instanceof PointerEvent).to.be.true;
611
+ });
@@ -1,5 +1,5 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
- import { aTimeout, assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
2
+ import { aTimeout, assert, elementUpdated, expect, fixture, html, oneEvent, } from '@open-wc/testing';
3
3
  import { sendKeys } from '@web/test-runner-commands';
4
4
  import { sendMouse } from '@web/test-runner-commands';
5
5
  import GlideCoreDropdown from './dropdown.js';
@@ -1056,11 +1056,11 @@ it('remains open when a tag is clicked', async () => {
1056
1056
  await elementUpdated(component);
1057
1057
  expect(component.open).to.be.true;
1058
1058
  });
1059
- it('does not select an option on Enter when the option is not focused', async () => {
1060
- const component = await fixture(html `<glide-core-dropdown
1059
+ it('cannot be tabbed to when `disabled`', async () => {
1060
+ await fixture(html `<glide-core-dropdown
1061
1061
  label="Label"
1062
1062
  placeholder="Placeholder"
1063
- open
1063
+ disabled
1064
1064
  multiple
1065
1065
  >
1066
1066
  <glide-core-dropdown-option
@@ -1073,23 +1073,11 @@ it('does not select an option on Enter when the option is not focused', async ()
1073
1073
  value="two"
1074
1074
  ></glide-core-dropdown-option>
1075
1075
  </glide-core-dropdown>`);
1076
- // Wait for it to open.
1077
- await aTimeout(0);
1078
- const option = component.querySelector('glide-core-dropdown-option');
1079
- option?.focus();
1080
- await sendKeys({ down: 'Tab' });
1081
- await sendKeys({ down: 'Shift' });
1082
- await sendKeys({ up: 'Tab' });
1083
- await sendKeys({ press: 'Enter' });
1084
- expect(option?.selected).to.be.false;
1076
+ await sendKeys({ press: 'Tab' });
1077
+ expect(document.activeElement).to.equal(document.body);
1085
1078
  });
1086
- it('cannot be tabbed to when `disabled`', async () => {
1087
- await fixture(html `<glide-core-dropdown
1088
- label="Label"
1089
- placeholder="Placeholder"
1090
- disabled
1091
- multiple
1092
- >
1079
+ it('clicks the button when `click()` is called', async () => {
1080
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
1093
1081
  <glide-core-dropdown-option
1094
1082
  label="One"
1095
1083
  value="one"
@@ -1100,6 +1088,11 @@ it('cannot be tabbed to when `disabled`', async () => {
1100
1088
  value="two"
1101
1089
  ></glide-core-dropdown-option>
1102
1090
  </glide-core-dropdown>`);
1103
- await sendKeys({ down: 'Tab' });
1104
- expect(document.activeElement).to.equal(document.body);
1091
+ const button = component.shadowRoot?.querySelector('[data-test="button"]');
1092
+ assert(button);
1093
+ setTimeout(() => {
1094
+ component.click();
1095
+ });
1096
+ const event = await oneEvent(button, 'click');
1097
+ expect(event instanceof PointerEvent).to.be.true;
1105
1098
  });
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
2
  import { ArgumentError } from 'ow';
3
- import { aTimeout, assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
3
+ import { aTimeout, assert, elementUpdated, expect, fixture, html, oneEvent, } from '@open-wc/testing';
4
4
  import { sendKeys } from '@web/test-runner-commands';
5
5
  import GlideCoreDropdown from './dropdown.js';
6
6
  import GlideCoreDropdownOption from './dropdown.option.js';
@@ -97,6 +97,35 @@ it('selects an option on Space', async () => {
97
97
  await sendKeys({ press: ' ' });
98
98
  expect(option?.selected).to.be.true;
99
99
  });
100
+ it('selects an option when its icon is clicked', async () => {
101
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
102
+ <glide-core-dropdown-option label="One" value="one">
103
+ <svg
104
+ slot="icon"
105
+ fill="none"
106
+ viewBox="0 0 24 24"
107
+ stroke-width="1.5"
108
+ stroke="currentColor"
109
+ style="height: 1rem; width: 1rem;"
110
+ >
111
+ <path
112
+ stroke-linecap="round"
113
+ stroke-linejoin="round"
114
+ d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"
115
+ />
116
+ </svg>
117
+ </glide-core-dropdown-option>
118
+ </glide-core-dropdown>`);
119
+ // Wait for it to open.
120
+ await aTimeout(0);
121
+ const option = component.querySelector('glide-core-dropdown-option');
122
+ option?.shadowRoot
123
+ ?.querySelector('[data-test="icon-slot"]')
124
+ ?.assignedElements()
125
+ ?.at(0)
126
+ ?.dispatchEvent(new Event('click', { bubbles: true }));
127
+ expect(option?.selected).to.be.true;
128
+ });
100
129
  it('does not deselect options on Space', async () => {
101
130
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
102
131
  <glide-core-dropdown-option
@@ -490,8 +519,8 @@ it('hides Select All', async () => {
490
519
  const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
491
520
  expect(selectAll?.checkVisibility()).to.not.be.ok;
492
521
  });
493
- it('does not select an option on Enter when the option is not focused', async () => {
494
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
522
+ it('cannot be tabbed to when `disabled`', async () => {
523
+ await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
495
524
  <glide-core-dropdown-option
496
525
  label="One"
497
526
  value="one"
@@ -502,28 +531,21 @@ it('does not select an option on Enter when the option is not focused', async ()
502
531
  value="two"
503
532
  ></glide-core-dropdown-option>
504
533
  </glide-core-dropdown>`);
505
- // Wait for it to open.
506
- await aTimeout(0);
507
- const option = component.querySelector('glide-core-dropdown-option');
508
- option?.focus();
509
534
  await sendKeys({ down: 'Tab' });
510
- await sendKeys({ down: 'Shift' });
511
- await sendKeys({ up: 'Tab' });
512
- await sendKeys({ press: 'Enter' });
513
- expect(option?.selected).to.be.false;
535
+ expect(document.activeElement).to.equal(document.body);
514
536
  });
515
- it('cannot be tabbed to when `disabled`', async () => {
516
- await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
517
- <glide-core-dropdown-option
518
- label="One"
519
- value="one"
520
- ></glide-core-dropdown-option>
521
-
537
+ it('clicks the button when `click()` is called', async () => {
538
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
522
539
  <glide-core-dropdown-option
523
- label="Two"
524
- value="two"
540
+ label="Label"
541
+ value="value"
525
542
  ></glide-core-dropdown-option>
526
543
  </glide-core-dropdown>`);
527
- await sendKeys({ down: 'Tab' });
528
- expect(document.activeElement).to.equal(document.body);
544
+ const button = component.shadowRoot?.querySelector('[data-test="button"]');
545
+ assert(button);
546
+ setTimeout(() => {
547
+ component.click();
548
+ });
549
+ const event = await oneEvent(button, 'click');
550
+ expect(event instanceof PointerEvent).to.be.true;
529
551
  });
@@ -7,4 +7,4 @@ import './radio.js';
7
7
  import type { Meta, StoryObj } from '@storybook/web-components';
8
8
  declare const meta: Meta;
9
9
  export default meta;
10
- export declare const SingleSelectionHorizontal: StoryObj;
10
+ export declare const FormControlsLayout: StoryObj;
@@ -17,7 +17,7 @@ export default class GlideCoreIconButton extends LitElement {
17
17
  ariaExpanded: 'true' | 'false' | null;
18
18
  ariaHasPopup: 'true' | 'false' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | null;
19
19
  disabled: boolean;
20
- /** Text read aloud for screenreaders. For accessibility, this should always be provided. */
20
+ /** For screenreaders. Required. */
21
21
  label: string;
22
22
  variant: 'primary' | 'secondary' | 'tertiary';
23
23
  firstUpdated(): void;
@@ -3,6 +3,4 @@ import './icons/storybook.js';
3
3
  import type { Meta, StoryObj } from '@storybook/web-components';
4
4
  declare const meta: Meta;
5
5
  export default meta;
6
- export declare const Primary: StoryObj;
7
- export declare const Secondary: StoryObj;
8
- export declare const Tertiary: StoryObj;
6
+ export declare const IconButton: StoryObj;
@@ -1,4 +1,6 @@
1
1
  import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export default[css`
2
+ ${focusOutline(".component:focus-visible")}
3
+ `,css`
2
4
  :host {
3
5
  /* Contains elements with "padding" and "width". Inline by default. */
4
6
  display: inline-flex;
@@ -24,10 +26,6 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export
24
26
  outline: none;
25
27
  }
26
28
 
27
- &:focus-visible {
28
- ${focusOutline};
29
- }
30
-
31
29
  &:disabled {
32
30
  cursor: not-allowed;
33
31
  opacity: 1;
@@ -1,2 +1,7 @@
1
+ /**
2
+ * The class="check" on the path below is used as a CSS selector
3
+ * in checkbox.styles.ts. Please be cautious when making changes
4
+ * here as to not break the Checkbox selectors.
5
+ */
1
6
  declare const _default: import("lit").TemplateResult<1>;
2
7
  export default _default;
@@ -1 +1 @@
1
- import{html}from"lit";export default html`<svg fill="none" viewBox="0 0 24 24" style="height: var(--size, 0.875rem); width: var(--size, 0.875rem);"><path d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
1
+ import{html}from"lit";export default html`<svg aria-hidden="true" fill="none" viewBox="0 0 24 24" style="height: var(--size, 0.875rem); width: var(--size, 0.875rem);"><path class="check" d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
package/dist/input.d.ts CHANGED
@@ -24,7 +24,7 @@ export default class GlideCoreInput extends LitElement {
24
24
  #private;
25
25
  static formAssociated: boolean;
26
26
  static shadowRootOptions: ShadowRootInit;
27
- static styles: import("lit").CSSResult;
27
+ static styles: import("lit").CSSResult[];
28
28
  type: SupportedTypes;
29
29
  name?: string;
30
30
  value: string;