@internetarchive/modal-manager 2.0.3 → 2.0.4-alpha-webdev7960.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.
Files changed (103) hide show
  1. package/.editorconfig +29 -29
  2. package/.eslintrc.js +14 -14
  3. package/.github/workflows/ci.yml +30 -30
  4. package/.github/workflows/gh-pages-main.yml +42 -42
  5. package/.github/workflows/pr-preview.yml +40 -40
  6. package/LICENSE +661 -661
  7. package/README.md +139 -139
  8. package/custom-elements.json +170 -170
  9. package/dist/index.d.ts +7 -7
  10. package/dist/index.js +5 -5
  11. package/dist/index.js.map +1 -1
  12. package/dist/src/assets/arrow-left-icon.d.ts +2 -2
  13. package/dist/src/assets/arrow-left-icon.js +14 -14
  14. package/dist/src/assets/arrow-left-icon.js.map +1 -1
  15. package/dist/src/assets/ia-logo-icon.d.ts +2 -2
  16. package/dist/src/assets/ia-logo-icon.js +29 -29
  17. package/dist/src/assets/ia-logo-icon.js.map +1 -1
  18. package/dist/src/modal-config.d.ts +104 -104
  19. package/dist/src/modal-config.js +24 -24
  20. package/dist/src/modal-config.js.map +1 -1
  21. package/dist/src/modal-manager-host-bridge-interface.d.ts +12 -12
  22. package/dist/src/modal-manager-host-bridge-interface.js +1 -1
  23. package/dist/src/modal-manager-host-bridge-interface.js.map +1 -1
  24. package/dist/src/modal-manager-host-bridge.d.ts +34 -34
  25. package/dist/src/modal-manager-host-bridge.js +62 -62
  26. package/dist/src/modal-manager-host-bridge.js.map +1 -1
  27. package/dist/src/modal-manager-interface.d.ts +27 -27
  28. package/dist/src/modal-manager-interface.js +1 -1
  29. package/dist/src/modal-manager-interface.js.map +1 -1
  30. package/dist/src/modal-manager-mode.d.ts +10 -10
  31. package/dist/src/modal-manager-mode.js +11 -11
  32. package/dist/src/modal-manager-mode.js.map +1 -1
  33. package/dist/src/modal-manager.d.ts +137 -127
  34. package/dist/src/modal-manager.js +247 -234
  35. package/dist/src/modal-manager.js.map +1 -1
  36. package/dist/src/modal-template.d.ts +41 -41
  37. package/dist/src/modal-template.js +335 -335
  38. package/dist/src/modal-template.js.map +1 -1
  39. package/dist/src/shoelace/active-elements.d.ts +15 -15
  40. package/dist/src/shoelace/active-elements.js +27 -27
  41. package/dist/src/shoelace/active-elements.js.map +1 -1
  42. package/dist/src/shoelace/modal.d.ts +24 -24
  43. package/dist/src/shoelace/modal.js +131 -131
  44. package/dist/src/shoelace/modal.js.map +1 -1
  45. package/dist/src/shoelace/tabbable.d.ts +9 -9
  46. package/dist/src/shoelace/tabbable.js +169 -169
  47. package/dist/src/shoelace/tabbable.js.map +1 -1
  48. package/dist/test/modal-config.test.d.ts +1 -1
  49. package/dist/test/modal-config.test.js +69 -69
  50. package/dist/test/modal-config.test.js.map +1 -1
  51. package/dist/test/modal-manager.test.d.ts +1 -1
  52. package/dist/test/modal-manager.test.js +274 -274
  53. package/dist/test/modal-manager.test.js.map +1 -1
  54. package/dist/test/modal-template.test.d.ts +1 -1
  55. package/dist/test/modal-template.test.js +178 -178
  56. package/dist/test/modal-template.test.js.map +1 -1
  57. package/dist/vite.config.d.ts +2 -2
  58. package/dist/vite.config.js +22 -22
  59. package/dist/vite.config.js.map +1 -1
  60. package/docs/assets/css/main.css +2678 -2678
  61. package/docs/classes/_src_modal_config_.modalconfig.html +429 -429
  62. package/docs/classes/_src_modal_manager_.modalmanager.html +7702 -7702
  63. package/docs/classes/_src_modal_manager_host_bridge_.modalmanagerhostbridge.html +409 -409
  64. package/docs/classes/_src_modal_template_.modaltemplate.html +7096 -7096
  65. package/docs/enums/_src_modal_manager_mode_.modalmanagermode.html +196 -196
  66. package/docs/globals.html +150 -150
  67. package/docs/index.html +252 -252
  68. package/docs/interfaces/_src_modal_manager_host_bridge_interface_.modalmanagerhostbridgeinterface.html +210 -210
  69. package/docs/interfaces/_src_modal_manager_interface_.modalmanagerinterface.html +7095 -7095
  70. package/docs/modules/_index_.html +208 -208
  71. package/docs/modules/_src_modal_config_.html +146 -146
  72. package/docs/modules/_src_modal_manager_.html +146 -146
  73. package/docs/modules/_src_modal_manager_host_bridge_.html +146 -146
  74. package/docs/modules/_src_modal_manager_host_bridge_interface_.html +146 -146
  75. package/docs/modules/_src_modal_manager_interface_.html +146 -146
  76. package/docs/modules/_src_modal_manager_mode_.html +146 -146
  77. package/docs/modules/_src_modal_template_.html +146 -146
  78. package/docs/modules/_test_modal_config_test_.html +106 -106
  79. package/docs/modules/_test_modal_manager_test_.html +106 -106
  80. package/docs/modules/_test_modal_template_test_.html +106 -106
  81. package/index.html +300 -300
  82. package/index.ts +7 -7
  83. package/karma.conf.js +24 -24
  84. package/package.json +85 -85
  85. package/renovate.json +7 -7
  86. package/src/assets/arrow-left-icon.ts +15 -15
  87. package/src/assets/ia-logo-icon.ts +30 -30
  88. package/src/modal-config.ts +133 -133
  89. package/src/modal-manager-host-bridge-interface.ts +13 -13
  90. package/src/modal-manager-host-bridge.ts +82 -82
  91. package/src/modal-manager-interface.ts +30 -30
  92. package/src/modal-manager-mode.ts +10 -10
  93. package/src/modal-manager.ts +303 -283
  94. package/src/modal-template.ts +343 -343
  95. package/src/shoelace/LICENSE.md +6 -6
  96. package/src/shoelace/active-elements.ts +33 -33
  97. package/src/shoelace/modal.ts +166 -166
  98. package/src/shoelace/tabbable.ts +223 -223
  99. package/test/modal-config.test.ts +77 -77
  100. package/test/modal-manager.test.ts +347 -347
  101. package/test/modal-template.test.ts +206 -206
  102. package/tsconfig.json +21 -21
  103. package/vite.config.ts +23 -23
@@ -1,347 +1,347 @@
1
- import { fixture, expect, oneEvent, elementUpdated } from '@open-wc/testing';
2
- import { TemplateResult, html } from 'lit';
3
-
4
- import '../src/modal-manager';
5
- import { ModalConfig } from '../src/modal-config';
6
- import { ModalManager } from '../src/modal-manager';
7
- import { ModalManagerMode } from '../src/modal-manager-mode';
8
- import { ModalManagerInterface } from '../src/modal-manager-interface';
9
-
10
- import { getTabbableElements } from '../src/shoelace/tabbable';
11
-
12
- describe('Modal Manager', () => {
13
- it('defaults to closed', async () => {
14
- const el = (await fixture(html`
15
- <modal-manager></modal-manager>
16
- `)) as ModalManager;
17
-
18
- expect(el.mode).to.equal('closed');
19
- });
20
-
21
- it('can be closed by calling closeModal', async () => {
22
- const el = (await fixture(html`
23
- <modal-manager .mode=${ModalManagerMode.Open}></modal-manager>
24
- `)) as ModalManager;
25
-
26
- el.customModalContent = 'foo' as unknown as TemplateResult;
27
- await elementUpdated(el);
28
-
29
- expect(el.customModalContent).to.equal('foo');
30
- el.closeModal();
31
- await elementUpdated(el);
32
-
33
- expect(el.mode).to.equal('closed');
34
- expect(el.customModalContent).to.equal(undefined);
35
- });
36
-
37
- it('can be closed by clicking on the backdrop', async () => {
38
- const el = (await fixture(html`
39
- <modal-manager .mode=${ModalManagerMode.Open}></modal-manager>
40
- `)) as ModalManager;
41
-
42
- const backdrop = el.shadowRoot?.querySelector('.backdrop');
43
- const clickEvent = new MouseEvent('click');
44
-
45
- backdrop?.dispatchEvent(clickEvent);
46
- await elementUpdated(el);
47
-
48
- expect(el.mode).to.equal('closed');
49
- });
50
-
51
- it('emits a modeChanged event when opening', async () => {
52
- const el = (await fixture(html`
53
- <modal-manager></modal-manager>
54
- `)) as ModalManager;
55
-
56
- const config = new ModalConfig();
57
-
58
- setTimeout(() => {
59
- el.showModal({ config });
60
- });
61
- const response = await oneEvent(el, 'modeChanged', false);
62
- expect(response.detail.mode).to.equal(ModalManagerMode.Open);
63
- });
64
-
65
- it('emits a modeChanged event when closing', async () => {
66
- const el = (await fixture(html`
67
- <modal-manager></modal-manager>
68
- `)) as ModalManager;
69
-
70
- const config = new ModalConfig();
71
- el.showModal({ config });
72
- await elementUpdated(el);
73
-
74
- setTimeout(() => {
75
- el.closeModal();
76
- });
77
- const response = await oneEvent(el, 'modeChanged', false);
78
- expect(response.detail.mode).to.equal(ModalManagerMode.Closed);
79
- });
80
-
81
- it('can show a modal', async () => {
82
- const el = (await fixture(html`
83
- <modal-manager></modal-manager>
84
- `)) as ModalManager;
85
-
86
- const config = new ModalConfig();
87
- el.showModal({ config });
88
- await elementUpdated(el);
89
- expect(el.mode).to.equal(ModalManagerMode.Open);
90
- });
91
-
92
- it('sets the --containerHeight CSS property when the window resizes', async () => {
93
- const el = (await fixture(html`
94
- <modal-manager></modal-manager>
95
- `)) as ModalManager;
96
-
97
- const config = new ModalConfig();
98
- el.showModal({ config });
99
- await elementUpdated(el);
100
- const event = new Event('resize');
101
- const propBefore = el.style.getPropertyValue('--containerHeight');
102
- expect(propBefore).to.equal('');
103
- window.dispatchEvent(event);
104
- await elementUpdated(el);
105
- const propAfter = el.style.getPropertyValue('--containerHeight');
106
- expect(propAfter).to.not.equal('');
107
- });
108
-
109
- it('calls the userClosedModalCallback when the user taps the backdrop', async () => {
110
- const el = (await fixture(html`
111
- <modal-manager></modal-manager>
112
- `)) as ModalManager;
113
-
114
- const config = new ModalConfig();
115
- let callbackCalled = false;
116
- const callback = (): void => {
117
- callbackCalled = true;
118
- };
119
- el.showModal({
120
- config,
121
- userClosedModalCallback: callback,
122
- });
123
- await elementUpdated(el);
124
-
125
- const backdrop = el.shadowRoot?.querySelector('.backdrop');
126
- const clickEvent = new MouseEvent('click');
127
- backdrop?.dispatchEvent(clickEvent);
128
-
129
- await elementUpdated(el);
130
-
131
- expect(callbackCalled).to.equal(true);
132
- });
133
-
134
- it('does not call the userClosedModalCallback when the modal just closes', async () => {
135
- const el = (await fixture(html`
136
- <modal-manager></modal-manager>
137
- `)) as ModalManager;
138
-
139
- const config = new ModalConfig();
140
- let callbackCalled = false;
141
- const callback = (): void => {
142
- callbackCalled = true;
143
- };
144
- el.showModal({
145
- config,
146
- userClosedModalCallback: callback,
147
- });
148
- await elementUpdated(el);
149
- el.closeModal();
150
- await elementUpdated(el);
151
- expect(callbackCalled).to.equal(false);
152
- });
153
-
154
- it('calls the userPressedLeftNavButtonCallback when the user clicks the left nav button', async () => {
155
- const el = (await fixture(html`
156
- <modal-manager></modal-manager>
157
- `)) as ModalManager;
158
-
159
- const config = new ModalConfig();
160
- config.showLeftNavButton = true;
161
-
162
- let callbackCalled = false;
163
- const callback = (): void => {
164
- callbackCalled = true;
165
- };
166
- el.showModal({
167
- config,
168
- userPressedLeftNavButtonCallback: callback,
169
- });
170
- await elementUpdated(el);
171
-
172
- const modalTemplate = el.shadowRoot?.querySelector('modal-template');
173
- expect(modalTemplate).to.exist;
174
-
175
- modalTemplate?.dispatchEvent(new Event('leftNavButtonPressed'));
176
-
177
- await elementUpdated(el);
178
-
179
- expect(callbackCalled).to.equal(true);
180
- });
181
-
182
- it('mode is set to closed when close button is pressed', async () => {
183
- const el = (await fixture(html`
184
- <modal-manager></modal-manager>
185
- `)) as ModalManager;
186
-
187
- const config = new ModalConfig();
188
- el.showModal({ config });
189
- await elementUpdated(el);
190
-
191
- expect(el.mode).to.equal('open');
192
-
193
- const modal = el.shadowRoot?.querySelector('modal-template');
194
- const closeButton = modal?.shadowRoot?.querySelector('.close-button');
195
- const clickEvent = new MouseEvent('click');
196
- closeButton?.dispatchEvent(clickEvent);
197
-
198
- await elementUpdated(el);
199
-
200
- expect(el.mode).to.equal('closed');
201
- });
202
-
203
- it('mode is set to closed when close button gets spacebar pressed', async () => {
204
- const el = (await fixture(html`
205
- <modal-manager></modal-manager>
206
- `)) as ModalManager;
207
-
208
- const config = new ModalConfig();
209
- el.showModal({ config });
210
- await elementUpdated(el);
211
-
212
- expect(el.mode).to.equal('open');
213
-
214
- const modal = el.shadowRoot?.querySelector('modal-template');
215
- const closeButton = modal?.shadowRoot?.querySelector('.close-button');
216
-
217
- // Close with keyboard
218
- const spacebarEvent = new KeyboardEvent('keydown', { key: ' ' });
219
- closeButton?.dispatchEvent(spacebarEvent);
220
-
221
- await elementUpdated(el);
222
-
223
- expect(el.mode).to.equal('closed');
224
- });
225
-
226
- it('mode remains open when close button gets non-button keypress', async () => {
227
- const el = (await fixture(html`
228
- <modal-manager></modal-manager>
229
- `)) as ModalManager;
230
-
231
- const config = new ModalConfig();
232
- el.showModal({ config });
233
- await elementUpdated(el);
234
-
235
- expect(el.mode).to.equal('open');
236
-
237
- const modal = el.shadowRoot?.querySelector('modal-template');
238
- const closeButton = modal?.shadowRoot?.querySelector('.close-button');
239
-
240
- // Close with keyboard
241
- const keyboardEvent = new KeyboardEvent('keydown', { key: '.' });
242
- closeButton?.dispatchEvent(keyboardEvent);
243
-
244
- await elementUpdated(el);
245
-
246
- expect(el.mode).to.equal('open');
247
- });
248
-
249
- it('allows the user to close by clicking on the backdrop if configured to', async () => {
250
- const el = (await fixture(html`
251
- <modal-manager></modal-manager>
252
- `)) as ModalManager;
253
-
254
- const config = new ModalConfig();
255
- config.closeOnBackdropClick = true;
256
- el.showModal({ config });
257
- await elementUpdated(el);
258
-
259
- const backdrop = el.shadowRoot?.querySelector('.backdrop');
260
- const clickEvent = new MouseEvent('click');
261
- backdrop?.dispatchEvent(clickEvent);
262
-
263
- await elementUpdated(el);
264
-
265
- expect(el.mode).to.equal('closed');
266
- });
267
-
268
- it("doesn't allow the user to close by clicking on the backdrop if configured to", async () => {
269
- const el = (await fixture(html`
270
- <modal-manager></modal-manager>
271
- `)) as ModalManagerInterface;
272
-
273
- const config = new ModalConfig();
274
- config.closeOnBackdropClick = false;
275
- el.showModal({ config });
276
- await elementUpdated(el);
277
-
278
- const backdrop = el.shadowRoot?.querySelector('.backdrop');
279
- const clickEvent = new MouseEvent('click');
280
- backdrop?.dispatchEvent(clickEvent);
281
-
282
- await elementUpdated(el);
283
-
284
- expect(el.getMode()).to.equal('open');
285
- });
286
-
287
- it('ia logo should not visible on modal', async () => {
288
- const el = (await fixture(html`
289
- <modal-manager></modal-manager>
290
- `)) as ModalManagerInterface;
291
-
292
- const config = new ModalConfig();
293
- config.showHeaderLogo = false;
294
- el.showModal({ config });
295
- await elementUpdated(el);
296
-
297
- const logoIcon = el.shadowRoot?.querySelector('.logo-icon');
298
- expect(logoIcon).to.not.exist;
299
- });
300
-
301
- it('should trap Tab key', async () => {
302
- const el = (await fixture(html`
303
- <modal-manager></modal-manager>
304
- `)) as ModalManager;
305
-
306
- const config = new ModalConfig();
307
- el.showModal({ config });
308
- await elementUpdated(el);
309
-
310
- expect(el.mode).to.equal('open');
311
-
312
- // Tab once to focus
313
- const tabEvent = new KeyboardEvent('keydown', { key: 'Tab' });
314
- document.dispatchEvent(tabEvent);
315
- await elementUpdated(el);
316
-
317
- // Should be only one tabbable element
318
- const modal = el.shadowRoot?.querySelector('modal-template') as HTMLElement;
319
- const tabbableElements = getTabbableElements(modal);
320
- expect(tabbableElements?.length).to.equal(1);
321
-
322
- const closeButton = modal?.shadowRoot?.querySelector(
323
- '.close-button'
324
- ) as HTMLElement;
325
- const activeElement = modal?.shadowRoot?.activeElement as HTMLElement;
326
-
327
- expect(activeElement).to.equal(closeButton);
328
-
329
- // Tab again
330
- el.dispatchEvent(tabEvent);
331
- await elementUpdated(el);
332
-
333
- // Should be only one tabbable element
334
- expect(activeElement).to.equal(closeButton);
335
-
336
- // Shift + Tab
337
- const shiftTabEvent = new KeyboardEvent('keydown', {
338
- key: 'Tab',
339
- shiftKey: true,
340
- });
341
- document.dispatchEvent(shiftTabEvent);
342
- await elementUpdated(el);
343
-
344
- // Should be only one tabbable element
345
- expect(activeElement).to.equal(closeButton);
346
- });
347
- });
1
+ import { fixture, expect, oneEvent, elementUpdated } from '@open-wc/testing';
2
+ import { TemplateResult, html } from 'lit';
3
+
4
+ import '../src/modal-manager';
5
+ import { ModalConfig } from '../src/modal-config';
6
+ import { ModalManager } from '../src/modal-manager';
7
+ import { ModalManagerMode } from '../src/modal-manager-mode';
8
+ import { ModalManagerInterface } from '../src/modal-manager-interface';
9
+
10
+ import { getTabbableElements } from '../src/shoelace/tabbable';
11
+
12
+ describe('Modal Manager', () => {
13
+ it('defaults to closed', async () => {
14
+ const el = (await fixture(html`
15
+ <modal-manager></modal-manager>
16
+ `)) as ModalManager;
17
+
18
+ expect(el.mode).to.equal('closed');
19
+ });
20
+
21
+ it('can be closed by calling closeModal', async () => {
22
+ const el = (await fixture(html`
23
+ <modal-manager .mode=${ModalManagerMode.Open}></modal-manager>
24
+ `)) as ModalManager;
25
+
26
+ el.customModalContent = 'foo' as unknown as TemplateResult;
27
+ await elementUpdated(el);
28
+
29
+ expect(el.customModalContent).to.equal('foo');
30
+ el.closeModal();
31
+ await elementUpdated(el);
32
+
33
+ expect(el.mode).to.equal('closed');
34
+ expect(el.customModalContent).to.equal(undefined);
35
+ });
36
+
37
+ it('can be closed by clicking on the backdrop', async () => {
38
+ const el = (await fixture(html`
39
+ <modal-manager .mode=${ModalManagerMode.Open}></modal-manager>
40
+ `)) as ModalManager;
41
+
42
+ const backdrop = el.shadowRoot?.querySelector('.backdrop');
43
+ const clickEvent = new MouseEvent('click');
44
+
45
+ backdrop?.dispatchEvent(clickEvent);
46
+ await elementUpdated(el);
47
+
48
+ expect(el.mode).to.equal('closed');
49
+ });
50
+
51
+ it('emits a modeChanged event when opening', async () => {
52
+ const el = (await fixture(html`
53
+ <modal-manager></modal-manager>
54
+ `)) as ModalManager;
55
+
56
+ const config = new ModalConfig();
57
+
58
+ setTimeout(() => {
59
+ el.showModal({ config });
60
+ });
61
+ const response = await oneEvent(el, 'modeChanged', false);
62
+ expect(response.detail.mode).to.equal(ModalManagerMode.Open);
63
+ });
64
+
65
+ it('emits a modeChanged event when closing', async () => {
66
+ const el = (await fixture(html`
67
+ <modal-manager></modal-manager>
68
+ `)) as ModalManager;
69
+
70
+ const config = new ModalConfig();
71
+ el.showModal({ config });
72
+ await elementUpdated(el);
73
+
74
+ setTimeout(() => {
75
+ el.closeModal();
76
+ });
77
+ const response = await oneEvent(el, 'modeChanged', false);
78
+ expect(response.detail.mode).to.equal(ModalManagerMode.Closed);
79
+ });
80
+
81
+ it('can show a modal', async () => {
82
+ const el = (await fixture(html`
83
+ <modal-manager></modal-manager>
84
+ `)) as ModalManager;
85
+
86
+ const config = new ModalConfig();
87
+ el.showModal({ config });
88
+ await elementUpdated(el);
89
+ expect(el.mode).to.equal(ModalManagerMode.Open);
90
+ });
91
+
92
+ it('sets the --containerHeight CSS property when the window resizes', async () => {
93
+ const el = (await fixture(html`
94
+ <modal-manager></modal-manager>
95
+ `)) as ModalManager;
96
+
97
+ const config = new ModalConfig();
98
+ el.showModal({ config });
99
+ await elementUpdated(el);
100
+ const event = new Event('resize');
101
+ const propBefore = el.style.getPropertyValue('--containerHeight');
102
+ expect(propBefore).to.equal('');
103
+ window.dispatchEvent(event);
104
+ await elementUpdated(el);
105
+ const propAfter = el.style.getPropertyValue('--containerHeight');
106
+ expect(propAfter).to.not.equal('');
107
+ });
108
+
109
+ it('calls the userClosedModalCallback when the user taps the backdrop', async () => {
110
+ const el = (await fixture(html`
111
+ <modal-manager></modal-manager>
112
+ `)) as ModalManager;
113
+
114
+ const config = new ModalConfig();
115
+ let callbackCalled = false;
116
+ const callback = (): void => {
117
+ callbackCalled = true;
118
+ };
119
+ el.showModal({
120
+ config,
121
+ userClosedModalCallback: callback,
122
+ });
123
+ await elementUpdated(el);
124
+
125
+ const backdrop = el.shadowRoot?.querySelector('.backdrop');
126
+ const clickEvent = new MouseEvent('click');
127
+ backdrop?.dispatchEvent(clickEvent);
128
+
129
+ await elementUpdated(el);
130
+
131
+ expect(callbackCalled).to.equal(true);
132
+ });
133
+
134
+ it('does not call the userClosedModalCallback when the modal just closes', async () => {
135
+ const el = (await fixture(html`
136
+ <modal-manager></modal-manager>
137
+ `)) as ModalManager;
138
+
139
+ const config = new ModalConfig();
140
+ let callbackCalled = false;
141
+ const callback = (): void => {
142
+ callbackCalled = true;
143
+ };
144
+ el.showModal({
145
+ config,
146
+ userClosedModalCallback: callback,
147
+ });
148
+ await elementUpdated(el);
149
+ el.closeModal();
150
+ await elementUpdated(el);
151
+ expect(callbackCalled).to.equal(false);
152
+ });
153
+
154
+ it('calls the userPressedLeftNavButtonCallback when the user clicks the left nav button', async () => {
155
+ const el = (await fixture(html`
156
+ <modal-manager></modal-manager>
157
+ `)) as ModalManager;
158
+
159
+ const config = new ModalConfig();
160
+ config.showLeftNavButton = true;
161
+
162
+ let callbackCalled = false;
163
+ const callback = (): void => {
164
+ callbackCalled = true;
165
+ };
166
+ el.showModal({
167
+ config,
168
+ userPressedLeftNavButtonCallback: callback,
169
+ });
170
+ await elementUpdated(el);
171
+
172
+ const modalTemplate = el.shadowRoot?.querySelector('modal-template');
173
+ expect(modalTemplate).to.exist;
174
+
175
+ modalTemplate?.dispatchEvent(new Event('leftNavButtonPressed'));
176
+
177
+ await elementUpdated(el);
178
+
179
+ expect(callbackCalled).to.equal(true);
180
+ });
181
+
182
+ it('mode is set to closed when close button is pressed', async () => {
183
+ const el = (await fixture(html`
184
+ <modal-manager></modal-manager>
185
+ `)) as ModalManager;
186
+
187
+ const config = new ModalConfig();
188
+ el.showModal({ config });
189
+ await elementUpdated(el);
190
+
191
+ expect(el.mode).to.equal('open');
192
+
193
+ const modal = el.shadowRoot?.querySelector('modal-template');
194
+ const closeButton = modal?.shadowRoot?.querySelector('.close-button');
195
+ const clickEvent = new MouseEvent('click');
196
+ closeButton?.dispatchEvent(clickEvent);
197
+
198
+ await elementUpdated(el);
199
+
200
+ expect(el.mode).to.equal('closed');
201
+ });
202
+
203
+ it('mode is set to closed when close button gets spacebar pressed', async () => {
204
+ const el = (await fixture(html`
205
+ <modal-manager></modal-manager>
206
+ `)) as ModalManager;
207
+
208
+ const config = new ModalConfig();
209
+ el.showModal({ config });
210
+ await elementUpdated(el);
211
+
212
+ expect(el.mode).to.equal('open');
213
+
214
+ const modal = el.shadowRoot?.querySelector('modal-template');
215
+ const closeButton = modal?.shadowRoot?.querySelector('.close-button');
216
+
217
+ // Close with keyboard
218
+ const spacebarEvent = new KeyboardEvent('keydown', { key: ' ' });
219
+ closeButton?.dispatchEvent(spacebarEvent);
220
+
221
+ await elementUpdated(el);
222
+
223
+ expect(el.mode).to.equal('closed');
224
+ });
225
+
226
+ it('mode remains open when close button gets non-button keypress', async () => {
227
+ const el = (await fixture(html`
228
+ <modal-manager></modal-manager>
229
+ `)) as ModalManager;
230
+
231
+ const config = new ModalConfig();
232
+ el.showModal({ config });
233
+ await elementUpdated(el);
234
+
235
+ expect(el.mode).to.equal('open');
236
+
237
+ const modal = el.shadowRoot?.querySelector('modal-template');
238
+ const closeButton = modal?.shadowRoot?.querySelector('.close-button');
239
+
240
+ // Close with keyboard
241
+ const keyboardEvent = new KeyboardEvent('keydown', { key: '.' });
242
+ closeButton?.dispatchEvent(keyboardEvent);
243
+
244
+ await elementUpdated(el);
245
+
246
+ expect(el.mode).to.equal('open');
247
+ });
248
+
249
+ it('allows the user to close by clicking on the backdrop if configured to', async () => {
250
+ const el = (await fixture(html`
251
+ <modal-manager></modal-manager>
252
+ `)) as ModalManager;
253
+
254
+ const config = new ModalConfig();
255
+ config.closeOnBackdropClick = true;
256
+ el.showModal({ config });
257
+ await elementUpdated(el);
258
+
259
+ const backdrop = el.shadowRoot?.querySelector('.backdrop');
260
+ const clickEvent = new MouseEvent('click');
261
+ backdrop?.dispatchEvent(clickEvent);
262
+
263
+ await elementUpdated(el);
264
+
265
+ expect(el.mode).to.equal('closed');
266
+ });
267
+
268
+ it("doesn't allow the user to close by clicking on the backdrop if configured to", async () => {
269
+ const el = (await fixture(html`
270
+ <modal-manager></modal-manager>
271
+ `)) as ModalManagerInterface;
272
+
273
+ const config = new ModalConfig();
274
+ config.closeOnBackdropClick = false;
275
+ el.showModal({ config });
276
+ await elementUpdated(el);
277
+
278
+ const backdrop = el.shadowRoot?.querySelector('.backdrop');
279
+ const clickEvent = new MouseEvent('click');
280
+ backdrop?.dispatchEvent(clickEvent);
281
+
282
+ await elementUpdated(el);
283
+
284
+ expect(el.getMode()).to.equal('open');
285
+ });
286
+
287
+ it('ia logo should not visible on modal', async () => {
288
+ const el = (await fixture(html`
289
+ <modal-manager></modal-manager>
290
+ `)) as ModalManagerInterface;
291
+
292
+ const config = new ModalConfig();
293
+ config.showHeaderLogo = false;
294
+ el.showModal({ config });
295
+ await elementUpdated(el);
296
+
297
+ const logoIcon = el.shadowRoot?.querySelector('.logo-icon');
298
+ expect(logoIcon).to.not.exist;
299
+ });
300
+
301
+ it('should trap Tab key', async () => {
302
+ const el = (await fixture(html`
303
+ <modal-manager></modal-manager>
304
+ `)) as ModalManager;
305
+
306
+ const config = new ModalConfig();
307
+ el.showModal({ config });
308
+ await elementUpdated(el);
309
+
310
+ expect(el.mode).to.equal('open');
311
+
312
+ // Tab once to focus
313
+ const tabEvent = new KeyboardEvent('keydown', { key: 'Tab' });
314
+ document.dispatchEvent(tabEvent);
315
+ await elementUpdated(el);
316
+
317
+ // Should be only one tabbable element
318
+ const modal = el.shadowRoot?.querySelector('modal-template') as HTMLElement;
319
+ const tabbableElements = getTabbableElements(modal);
320
+ expect(tabbableElements?.length).to.equal(1);
321
+
322
+ const closeButton = modal?.shadowRoot?.querySelector(
323
+ '.close-button'
324
+ ) as HTMLElement;
325
+ const activeElement = modal?.shadowRoot?.activeElement as HTMLElement;
326
+
327
+ expect(activeElement).to.equal(closeButton);
328
+
329
+ // Tab again
330
+ el.dispatchEvent(tabEvent);
331
+ await elementUpdated(el);
332
+
333
+ // Should be only one tabbable element
334
+ expect(activeElement).to.equal(closeButton);
335
+
336
+ // Shift + Tab
337
+ const shiftTabEvent = new KeyboardEvent('keydown', {
338
+ key: 'Tab',
339
+ shiftKey: true,
340
+ });
341
+ document.dispatchEvent(shiftTabEvent);
342
+ await elementUpdated(el);
343
+
344
+ // Should be only one tabbable element
345
+ expect(activeElement).to.equal(closeButton);
346
+ });
347
+ });