@internetarchive/ia-item-navigator 1.0.4 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. package/.github/workflows/ci.yml +4 -5
  2. package/.github/workflows/gh-pages-main.yml +39 -0
  3. package/.github/workflows/pr-preview.yml +38 -0
  4. package/demo/app-root.ts +13 -13
  5. package/dist/demo/app-root.d.ts +47 -47
  6. package/dist/demo/app-root.js +200 -199
  7. package/dist/demo/app-root.js.map +1 -1
  8. package/dist/index.d.ts +3 -3
  9. package/dist/index.js +3 -3
  10. package/dist/src/interfaces/custom-theater-interface.d.ts +20 -20
  11. package/dist/src/interfaces/custom-theater-interface.js +1 -1
  12. package/dist/src/interfaces/event-interfaces.d.ts +40 -40
  13. package/dist/src/interfaces/event-interfaces.js +1 -1
  14. package/dist/src/interfaces/menu-interfaces.d.ts +23 -22
  15. package/dist/src/interfaces/menu-interfaces.js +1 -1
  16. package/dist/src/interfaces/menu-interfaces.js.map +1 -1
  17. package/dist/src/item-navigator.d.ts +69 -69
  18. package/dist/src/item-navigator.js +259 -257
  19. package/dist/src/item-navigator.js.map +1 -1
  20. package/dist/src/loader.d.ts +9 -13
  21. package/dist/src/loader.js +35 -31
  22. package/dist/src/loader.js.map +1 -1
  23. package/dist/src/menu-slider/ia-menu-slider.d.ts +31 -30
  24. package/dist/src/menu-slider/ia-menu-slider.js +123 -124
  25. package/dist/src/menu-slider/ia-menu-slider.js.map +1 -1
  26. package/dist/src/menu-slider/menu-button.d.ts +19 -19
  27. package/dist/src/menu-slider/menu-button.js +75 -75
  28. package/dist/src/menu-slider/menu-button.js.map +1 -1
  29. package/dist/src/menu-slider/styles/menu-button.d.ts +2 -2
  30. package/dist/src/menu-slider/styles/menu-button.js +2 -2
  31. package/dist/src/menu-slider/styles/menu-slider.d.ts +2 -2
  32. package/dist/src/menu-slider/styles/menu-slider.js +5 -5
  33. package/dist/src/no-theater-available.d.ts +9 -9
  34. package/dist/src/no-theater-available.js +35 -35
  35. package/dist/src/no-theater-available.js.map +1 -1
  36. package/dist/test/ia-item-navigator.test.d.ts +1 -1
  37. package/dist/test/ia-item-navigator.test.js +296 -296
  38. package/dist/test/ia-item-navigator.test.js.map +1 -1
  39. package/dist/test/ia-stub.d.ts +22 -22
  40. package/dist/test/ia-stub.js +34 -34
  41. package/dist/test/no-theater-available.test.d.ts +1 -1
  42. package/dist/test/no-theater-available.test.js +22 -22
  43. package/dist/test/no-theater-available.test.js.map +1 -1
  44. package/dist/vite.config.d.ts +2 -0
  45. package/dist/vite.config.js +25 -0
  46. package/dist/vite.config.js.map +1 -0
  47. package/package.json +35 -21
  48. package/src/interfaces/menu-interfaces.ts +3 -1
  49. package/src/item-navigator.ts +9 -4
  50. package/src/loader.ts +5 -7
  51. package/src/menu-slider/ia-menu-slider.ts +17 -17
  52. package/src/menu-slider/menu-button.ts +3 -3
  53. package/src/no-theater-available.ts +1 -1
  54. package/test/ia-item-navigator.test.ts +24 -24
  55. package/test/iaux-item-navigator.test.txt +417 -0
  56. package/test/iaux-sharing-options.test.txt +84 -0
  57. package/test/no-theater-available.test.ts +2 -2
  58. package/tsconfig.json +2 -1
  59. package/vite.config.ts +25 -0
@@ -24,7 +24,7 @@ describe('ItemNavigator', () => {
24
24
  describe('Theaters', () => {
25
25
  it('shows <ia-no-theater-available> if told', async () => {
26
26
  const el = await fixture<ItemNavigator>(
27
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
27
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
28
28
  );
29
29
  el.viewAvailable = false;
30
30
  await el.updateComplete;
@@ -33,7 +33,7 @@ describe('ItemNavigator', () => {
33
33
  });
34
34
  it('opens main slot by default', async () => {
35
35
  const el = await fixture<ItemNavigator>(
36
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
36
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
37
37
  );
38
38
 
39
39
  expect(el.viewAvailable).to.be.true;
@@ -45,23 +45,23 @@ describe('ItemNavigator', () => {
45
45
  describe('`el.loaded`', () => {
46
46
  it('toggles the spinning loader', async () => {
47
47
  const el = await fixture<ItemNavigator>(
48
- html`<ia-item-navigator></ia-item-navigator>`
48
+ html`<ia-item-navigator></ia-item-navigator>`,
49
49
  );
50
50
  expect(el.loaded).to.be.null; // initial load
51
51
  expect(el.shadowRoot?.querySelector('ia-itemnav-loader')).to.exist;
52
52
  });
53
53
  it('hides reader section if `!loaded`', async () => {
54
54
  const el = await fixture<ItemNavigator>(
55
- html`<ia-item-navigator></ia-item-navigator>`
55
+ html`<ia-item-navigator></ia-item-navigator>`,
56
56
  );
57
57
 
58
58
  expect(
59
- el.shadowRoot?.querySelector('#reader')?.getAttribute('class')
59
+ el.shadowRoot?.querySelector('#reader')?.getAttribute('class'),
60
60
  ).to.contain('hidden');
61
61
  });
62
62
  it('shows reader when `loaded` ', async () => {
63
63
  const el = await fixture<ItemNavigator>(
64
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
64
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
65
65
  );
66
66
 
67
67
  el.loaded = true;
@@ -75,7 +75,7 @@ describe('ItemNavigator', () => {
75
75
  });
76
76
  it('listens to `@loadingStateUpdated` to update `loaded` for <no-theater-available>', async () => {
77
77
  const el = await fixture<ItemNavigator>(
78
- html`<ia-item-navigator></ia-item-navigator>`
78
+ html`<ia-item-navigator></ia-item-navigator>`,
79
79
  );
80
80
 
81
81
  await el.updateComplete;
@@ -100,7 +100,7 @@ describe('ItemNavigator', () => {
100
100
  const el = await fixture<ItemNavigator>(
101
101
  html`<ia-item-navigator
102
102
  .sharedObserver=${sharedObserver}
103
- ></ia-item-navigator>`
103
+ ></ia-item-navigator>`,
104
104
  );
105
105
 
106
106
  expect(el.sharedObserver).to.equal(sharedObserver);
@@ -113,7 +113,7 @@ describe('ItemNavigator', () => {
113
113
  await fixture<ItemNavigator>(
114
114
  html`<ia-item-navigator
115
115
  .sharedObserver=${sharedObserver}
116
- ></ia-item-navigator>`
116
+ ></ia-item-navigator>`,
117
117
  );
118
118
 
119
119
  expect(addObserverSpy.callCount).to.equal(2);
@@ -125,7 +125,7 @@ describe('ItemNavigator', () => {
125
125
  const el = await fixture<ItemNavigator>(
126
126
  html`<ia-item-navigator
127
127
  .sharedObserver=${sharedObserver}
128
- ></ia-item-navigator>`
128
+ ></ia-item-navigator>`,
129
129
  );
130
130
 
131
131
  el.disconnectedCallback();
@@ -135,7 +135,7 @@ describe('ItemNavigator', () => {
135
135
  });
136
136
  it('sets menu to overlay if container width is <= 600px', async () => {
137
137
  const el = await fixture<ItemNavigator>(
138
- html`<ia-item-navigator></ia-item-navigator>`
138
+ html`<ia-item-navigator></ia-item-navigator>`,
139
139
  );
140
140
 
141
141
  expect(el.openMenuState).to.equal('shift'); // as starting point
@@ -162,7 +162,7 @@ describe('ItemNavigator', () => {
162
162
  it('uses one', async () => {
163
163
  const modal = new ModalManager();
164
164
  const el = await fixture<ItemNavigator>(
165
- html`<ia-item-navigator .modal=${modal}></ia-item-navigator>`
165
+ html`<ia-item-navigator .modal=${modal}></ia-item-navigator>`,
166
166
  );
167
167
  expect(el.modal).to.equal(modal);
168
168
  });
@@ -172,7 +172,7 @@ describe('ItemNavigator', () => {
172
172
  it('creates reflected attribute `viewportinfullscreen`', async () => {
173
173
  /** to help with external styling adjustmnents */
174
174
  const el = await fixture<ItemNavigator>(
175
- html`<ia-item-navigator></ia-item-navigator>`
175
+ html`<ia-item-navigator></ia-item-navigator>`,
176
176
  );
177
177
  expect(el.getAttribute('viewportinfullscreen')).to.be.null;
178
178
 
@@ -183,7 +183,7 @@ describe('ItemNavigator', () => {
183
183
  });
184
184
  it('@ViewportInFullScreen', async () => {
185
185
  const el = await fixture<ItemNavigator>(
186
- html`<ia-item-navigator></ia-item-navigator>`
186
+ html`<ia-item-navigator></ia-item-navigator>`,
187
187
  );
188
188
  expect(el.viewportInFullscreen).to.be.null;
189
189
 
@@ -211,7 +211,7 @@ describe('ItemNavigator', () => {
211
211
  describe('el.menuOpened', () => {
212
212
  it('toggles side menu open', async () => {
213
213
  const el = await fixture<ItemNavigator>(
214
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
214
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
215
215
  );
216
216
 
217
217
  el.menuContents = [menuProvider];
@@ -223,7 +223,7 @@ describe('ItemNavigator', () => {
223
223
  // side menu starts closed
224
224
  expect(el.menuOpened).to.be.false;
225
225
  expect(nav?.querySelector('#menu')?.getAttribute('class')).to.contain(
226
- 'hidden'
226
+ 'hidden',
227
227
  );
228
228
 
229
229
  // let's open menu
@@ -232,13 +232,13 @@ describe('ItemNavigator', () => {
232
232
 
233
233
  expect(el.menuOpened).to.be.true;
234
234
  expect(nav?.querySelector('#menu')?.getAttribute('class')).to.not.contain(
235
- 'hidden'
235
+ 'hidden',
236
236
  );
237
237
  });
238
238
 
239
239
  it('opens menu shortcut with `@manageSideMenuEvents`', async () => {
240
240
  const el = await fixture<ItemNavigator>(
241
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
241
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
242
242
  );
243
243
  const detail = {
244
244
  menuId: 'fullscreen',
@@ -303,7 +303,7 @@ describe('ItemNavigator', () => {
303
303
  describe('el.menuContents', () => {
304
304
  it('draws side menu when populated', async () => {
305
305
  const el = await fixture<ItemNavigator>(
306
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
306
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
307
307
  );
308
308
 
309
309
  el.menuContents = [menuProvider];
@@ -324,7 +324,7 @@ describe('ItemNavigator', () => {
324
324
  describe('`el.menuShortcuts`', () => {
325
325
  it('displays shortcut & toggle side menu button', async () => {
326
326
  const el = await fixture<ItemNavigator>(
327
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
327
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
328
328
  );
329
329
 
330
330
  const anotherShortcut = {
@@ -350,7 +350,7 @@ describe('ItemNavigator', () => {
350
350
  describe('Menu events', () => {
351
351
  it('`el.setMenuShortcuts`', async () => {
352
352
  const el = await fixture<ItemNavigator>(
353
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
353
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
354
354
  );
355
355
  expect(el.menuShortcuts.length).to.equal(0);
356
356
 
@@ -365,7 +365,7 @@ describe('ItemNavigator', () => {
365
365
  });
366
366
  it('`el.setMenuContents`', async () => {
367
367
  const el = await fixture<ItemNavigator>(
368
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
368
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
369
369
  );
370
370
  expect(el.menuContents.length).to.equal(0);
371
371
 
@@ -378,7 +378,7 @@ describe('ItemNavigator', () => {
378
378
  });
379
379
  it('`el.setOpenMenu`', async () => {
380
380
  const el = await fixture<ItemNavigator>(
381
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
381
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
382
382
  );
383
383
 
384
384
  el.setOpenMenu({
@@ -400,7 +400,7 @@ describe('ItemNavigator', () => {
400
400
  });
401
401
  it('`el.closeMenu`', async () => {
402
402
  const el = await fixture<ItemNavigator>(
403
- html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`
403
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
404
404
  );
405
405
 
406
406
  el.menuOpened = true;
@@ -0,0 +1,417 @@
1
+ /* eslint-disable camelcase */
2
+ import { html, fixture, expect } from '@open-wc/testing';
3
+ import Sinon from 'sinon';
4
+
5
+ import { SharedResizeObserver } from '@internetarchive/shared-resize-observer';
6
+ import { ModalManager } from '@internetarchive/modal-manager';
7
+ import { ItemNavigator } from '../src/iaux-item-navigator';
8
+ import '../src/iaux-item-navigator';
9
+
10
+ import { ItemStub, menuProvider, shortcut } from './ia-stub';
11
+ import {
12
+ ManageFullscreenEvent,
13
+ ToggleSideMenuOpenEvent,
14
+ SetSideMenuContentsEvent,
15
+ SetSideMenuShortcutsEvent,
16
+ ToggleSidePanelOpenEvent,
17
+ } from '../src/interfaces/event-interfaces';
18
+
19
+ afterEach(() => {
20
+ Sinon.restore();
21
+ });
22
+
23
+ describe('ItemNavigator', () => {
24
+ describe('Theaters', () => {
25
+ it('shows <ia-no-theater-available> if told', async () => {
26
+ const el = await fixture<ItemNavigator>(
27
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
28
+ );
29
+ el.viewAvailable = false;
30
+ await el.updateComplete;
31
+ expect(el.viewAvailable).to.be.false;
32
+ expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.exist;
33
+ });
34
+ it('opens main slot by default', async () => {
35
+ const el = await fixture<ItemNavigator>(
36
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
37
+ );
38
+
39
+ expect(el.viewAvailable).to.be.true;
40
+ expect(el.shadowRoot?.querySelector('ia-no-theater-available')).to.be
41
+ .null;
42
+ expect(el.shadowRoot?.querySelector('slot[name="main"]')).to.exist;
43
+ });
44
+ });
45
+ describe('`el.loaded`', () => {
46
+ it('toggles the spinning loader', async () => {
47
+ const el = await fixture<ItemNavigator>(
48
+ html`<ia-item-navigator></ia-item-navigator>`,
49
+ );
50
+ expect(el.loaded).to.be.null; // initial load
51
+ expect(el.shadowRoot?.querySelector('ia-itemnav-loader')).to.exist;
52
+ });
53
+ it('hides reader section if `!loaded`', async () => {
54
+ const el = await fixture<ItemNavigator>(
55
+ html`<ia-item-navigator></ia-item-navigator>`,
56
+ );
57
+
58
+ expect(
59
+ el.shadowRoot?.querySelector('#reader')?.getAttribute('class'),
60
+ ).to.contain('hidden');
61
+ });
62
+ it('shows reader when `loaded` ', async () => {
63
+ const el = await fixture<ItemNavigator>(
64
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
65
+ );
66
+
67
+ el.loaded = true;
68
+ await el.updateComplete;
69
+ const mainTheaterSection = el.shadowRoot?.querySelector('#reader');
70
+ expect(mainTheaterSection?.classList.contains('hide')).to.be.false;
71
+ expect(el.loaded).to.be.true;
72
+ // `loaded` property is reflected as DOM attribute
73
+ expect(el.hasAttribute('loaded')).to.equal(true);
74
+ expect(el.shadowRoot?.querySelector('slot[name="main"]')).to.exist;
75
+ });
76
+ it('listens to `@loadingStateUpdated` to update `loaded` for <no-theater-available>', async () => {
77
+ const el = await fixture<ItemNavigator>(
78
+ html`<ia-item-navigator></ia-item-navigator>`,
79
+ );
80
+
81
+ await el.updateComplete;
82
+ const spy = Sinon.spy();
83
+ el.loadingStateUpdated = spy;
84
+ el.loaded = null;
85
+ el.viewAvailable = false;
86
+ await el.updateComplete;
87
+ // check base properties
88
+ expect(el.loaded).to.equal(null);
89
+ expect(el.item).to.be.undefined;
90
+
91
+ // spy fires
92
+ expect(spy.called).to.equal(true);
93
+ expect(spy.callCount).to.equal(1);
94
+ });
95
+ });
96
+
97
+ describe('`el.sharedObserver`', () => {
98
+ it('uses one', async () => {
99
+ const sharedObserver = new SharedResizeObserver();
100
+ const el = await fixture<ItemNavigator>(
101
+ html`<ia-item-navigator
102
+ .sharedObserver=${sharedObserver}
103
+ ></ia-item-navigator>`,
104
+ );
105
+
106
+ expect(el.sharedObserver).to.equal(sharedObserver);
107
+ expect(typeof el.handleResize).to.equal('function');
108
+ });
109
+ it('freshly registers handlers', async () => {
110
+ const sharedObserver = new SharedResizeObserver();
111
+ const addObserverSpy = Sinon.spy(sharedObserver, 'addObserver');
112
+
113
+ await fixture<ItemNavigator>(
114
+ html`<ia-item-navigator
115
+ .sharedObserver=${sharedObserver}
116
+ ></ia-item-navigator>`,
117
+ );
118
+
119
+ expect(addObserverSpy.callCount).to.equal(2);
120
+ });
121
+ it('removes handler when component disconnects', async () => {
122
+ const sharedObserver = new SharedResizeObserver();
123
+ const removeObserverSpy = Sinon.spy(sharedObserver, 'removeObserver');
124
+
125
+ const el = await fixture<ItemNavigator>(
126
+ html`<ia-item-navigator
127
+ .sharedObserver=${sharedObserver}
128
+ ></ia-item-navigator>`,
129
+ );
130
+
131
+ el.disconnectedCallback();
132
+ await el.updateComplete;
133
+
134
+ expect(removeObserverSpy.callCount).to.equal(1);
135
+ });
136
+ it('sets menu to overlay if container width is <= 600px', async () => {
137
+ const el = await fixture<ItemNavigator>(
138
+ html`<ia-item-navigator></ia-item-navigator>`,
139
+ );
140
+
141
+ expect(el.openMenuState).to.equal('shift'); // as starting point
142
+
143
+ const overlaySize = {
144
+ contentRect: { width: 600 },
145
+ } as ResizeObserverEntry;
146
+ el.handleResize(overlaySize);
147
+ await el.updateComplete;
148
+
149
+ expect(el.openMenuState).to.equal('overlay'); // changes open menu display to an overlay
150
+
151
+ const shiftSize = {
152
+ contentRect: { width: 601 },
153
+ } as ResizeObserverEntry;
154
+ el.handleResize(shiftSize);
155
+ await el.updateComplete;
156
+
157
+ expect(el.openMenuState).to.equal('shift');
158
+ });
159
+ });
160
+
161
+ describe('`el.modal`', () => {
162
+ it('uses one', async () => {
163
+ const modal = new ModalManager();
164
+ const el = await fixture<ItemNavigator>(
165
+ html`<ia-item-navigator .modal=${modal}></ia-item-navigator>`,
166
+ );
167
+ expect(el.modal).to.equal(modal);
168
+ });
169
+ });
170
+
171
+ describe('full browser window immersion "fullscreen"', () => {
172
+ it('creates reflected attribute `viewportinfullscreen`', async () => {
173
+ /** to help with external styling adjustmnents */
174
+ const el = await fixture<ItemNavigator>(
175
+ html`<ia-item-navigator></ia-item-navigator>`,
176
+ );
177
+ expect(el.getAttribute('viewportinfullscreen')).to.be.null;
178
+
179
+ el.viewportInFullscreen = true;
180
+ await el.updateComplete;
181
+
182
+ expect(el.getAttribute('viewportinfullscreen')).to.exist;
183
+ });
184
+ it('@ViewportInFullScreen', async () => {
185
+ const el = await fixture<ItemNavigator>(
186
+ html`<ia-item-navigator></ia-item-navigator>`,
187
+ );
188
+ expect(el.viewportInFullscreen).to.be.null;
189
+
190
+ const yesFullscreenEvent = {
191
+ detail: {
192
+ isFullScreen: true,
193
+ },
194
+ } as ManageFullscreenEvent;
195
+ el.manageViewportFullscreen(yesFullscreenEvent);
196
+ await el.updateComplete;
197
+ expect(el.viewportInFullscreen).to.be.true;
198
+
199
+ const noFullscreenEvent = {
200
+ detail: {
201
+ isFullScreen: false,
202
+ },
203
+ } as ManageFullscreenEvent;
204
+ el.manageViewportFullscreen(noFullscreenEvent);
205
+ await el.updateComplete;
206
+ expect(el.viewportInFullscreen).to.be.null;
207
+ });
208
+ });
209
+
210
+ /* Side menu & shortcuts tests */
211
+ describe('el.menuOpened', () => {
212
+ it('toggles side menu open', async () => {
213
+ const el = await fixture<ItemNavigator>(
214
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
215
+ );
216
+
217
+ el.menuContents = [menuProvider];
218
+ await el.updateComplete;
219
+
220
+ const nav = el.shadowRoot?.querySelector('nav');
221
+
222
+ expect(nav?.querySelector('#menu')).to.exist;
223
+ // side menu starts closed
224
+ expect(el.menuOpened).to.be.false;
225
+ expect(nav?.querySelector('#menu')?.getAttribute('class')).to.contain(
226
+ 'hidden',
227
+ );
228
+
229
+ // let's open menu
230
+ el.toggleMenu();
231
+ await el.updateComplete;
232
+
233
+ expect(el.menuOpened).to.be.true;
234
+ expect(nav?.querySelector('#menu')?.getAttribute('class')).to.not.contain(
235
+ 'hidden',
236
+ );
237
+ });
238
+
239
+ it('opens menu shortcut with `@manageSideMenuEvents`', async () => {
240
+ const el = await fixture<ItemNavigator>(
241
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
242
+ );
243
+ const detail = {
244
+ menuId: 'fullscreen',
245
+ action: 'open',
246
+ };
247
+
248
+ el.menuContents = [menuProvider];
249
+ await el.updateComplete;
250
+ const frame = el.shadowRoot?.querySelector('#frame');
251
+ // default menu open behavior is to side menu open, not overlay
252
+ expect(frame?.getAttribute('class')).to.contain('shift');
253
+
254
+ expect(el.menuOpened).to.be.false;
255
+ expect(el.openMenu).to.be.undefined;
256
+ expect(frame?.getAttribute('class')).to.not.contain('open');
257
+
258
+ const event = new CustomEvent('updateSideMenu', {
259
+ detail,
260
+ }) as ToggleSideMenuOpenEvent;
261
+ el.manageSideMenuEvents(event);
262
+ await el.updateComplete;
263
+
264
+ expect(el.shouldRenderMenu).to.be.true;
265
+ expect(el.menuOpened).to.be.true;
266
+ expect(el.openMenu).to.equal(detail.menuId);
267
+
268
+ expect(frame?.getAttribute('class')).to.contain('open');
269
+
270
+ // no menu provided
271
+ const openShortcutSpy = Sinon.spy(el, 'openShortcut');
272
+ const toggleMenuSpy = Sinon.spy(el, 'toggleMenu');
273
+
274
+ const noMenuProvidedEvent = new CustomEvent('updateSideMenu', {
275
+ detail: {},
276
+ }) as any;
277
+ el.manageSideMenuEvents(noMenuProvidedEvent);
278
+ await el.updateComplete;
279
+
280
+ expect(openShortcutSpy.called).to.be.false;
281
+ expect(toggleMenuSpy.called).to.be.false;
282
+
283
+ // toggle menu
284
+ const toggleMenuEvent = new CustomEvent('updateSideMenu', {
285
+ detail: { action: 'toggle', menuId: 'fullscreen' },
286
+ }) as any;
287
+ el.manageSideMenuEvents(toggleMenuEvent);
288
+ await el.updateComplete;
289
+
290
+ expect(toggleMenuSpy.callCount).to.equal(1);
291
+
292
+ // open menu
293
+ const openMenuEvent = new CustomEvent('updateSideMenu', {
294
+ detail: { action: 'open', menuId: 'fullscreen' },
295
+ }) as any;
296
+ el.manageSideMenuEvents(openMenuEvent);
297
+ await el.updateComplete;
298
+
299
+ expect(openShortcutSpy.callCount).to.equal(1);
300
+ });
301
+ });
302
+
303
+ describe('el.menuContents', () => {
304
+ it('draws side menu when populated', async () => {
305
+ const el = await fixture<ItemNavigator>(
306
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
307
+ );
308
+
309
+ el.menuContents = [menuProvider];
310
+ await el.updateComplete;
311
+ expect(el.menuContents.length).to.exist;
312
+ expect(el.shouldRenderMenu).to.be.true;
313
+
314
+ const nav = el.shadowRoot?.querySelector('nav');
315
+ expect(nav).to.exist;
316
+
317
+ const menuSlider = nav?.querySelector('ia-menu-slider');
318
+ expect(menuSlider).to.exist;
319
+ expect(menuSlider?.getAttribute('manuallyhandleclose')).to.exist;
320
+ expect(menuSlider?.getAttribute('open')).to.exist;
321
+ });
322
+ });
323
+
324
+ describe('`el.menuShortcuts`', () => {
325
+ it('displays shortcut & toggle side menu button', async () => {
326
+ const el = await fixture<ItemNavigator>(
327
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
328
+ );
329
+
330
+ const anotherShortcut = {
331
+ id: 'foo',
332
+ icon: html`<i class="foo-shortcut"></i>`,
333
+ };
334
+ el.menuContents = [menuProvider];
335
+ el.menuShortcuts = [shortcut, anotherShortcut];
336
+ await el.updateComplete;
337
+
338
+ const nav = el.shadowRoot?.querySelector('nav');
339
+
340
+ const shortcutsContainer = nav?.querySelector('.shortcuts');
341
+ expect(el.menuShortcuts.length).to.exist;
342
+ expect(nav).to.exist;
343
+ expect(shortcutsContainer).to.exist;
344
+ expect(shortcutsContainer?.querySelector('i.fullscreen-test')).to.exist;
345
+ expect(shortcutsContainer?.querySelector('button.shortcut.foo')).to.exist;
346
+ expect(nav?.querySelector('.toggle-menu')).to.exist;
347
+ });
348
+ });
349
+
350
+ describe('Menu events', () => {
351
+ it('`el.setMenuShortcuts`', async () => {
352
+ const el = await fixture<ItemNavigator>(
353
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
354
+ );
355
+ expect(el.menuShortcuts.length).to.equal(0);
356
+
357
+ const menuShortcuts = [shortcut];
358
+
359
+ el.setMenuShortcuts({
360
+ detail: menuShortcuts,
361
+ } as SetSideMenuShortcutsEvent);
362
+ await el.updateComplete;
363
+
364
+ expect(el.menuShortcuts.length).to.equal(1);
365
+ });
366
+ it('`el.setMenuContents`', async () => {
367
+ const el = await fixture<ItemNavigator>(
368
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
369
+ );
370
+ expect(el.menuContents.length).to.equal(0);
371
+
372
+ el.setMenuShortcuts({
373
+ detail: [menuProvider],
374
+ } as SetSideMenuContentsEvent);
375
+ await el.updateComplete;
376
+
377
+ expect(el.menuShortcuts.length).to.equal(1);
378
+ });
379
+ it('`el.setOpenMenu`', async () => {
380
+ const el = await fixture<ItemNavigator>(
381
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
382
+ );
383
+
384
+ el.setOpenMenu({
385
+ detail: { id: 'foo' },
386
+ } as ToggleSidePanelOpenEvent);
387
+ await el.updateComplete;
388
+
389
+ expect(el.openMenu).to.equal('foo');
390
+ expect(el.selectedMenuId).to.equal('foo');
391
+
392
+ // toggles it off
393
+ el.setOpenMenu({
394
+ detail: { id: 'foo' },
395
+ } as ToggleSidePanelOpenEvent);
396
+ await el.updateComplete;
397
+
398
+ expect(el.openMenu).to.be.undefined;
399
+ expect(el.selectedMenuId).to.equal('');
400
+ });
401
+ it('`el.closeMenu`', async () => {
402
+ const el = await fixture<ItemNavigator>(
403
+ html`<ia-item-navigator .item=${new ItemStub()}></ia-item-navigator>`,
404
+ );
405
+
406
+ el.menuOpened = true;
407
+ await el.updateComplete;
408
+
409
+ expect(el.menuOpened).to.be.true;
410
+
411
+ el.closeMenu();
412
+ await el.updateComplete;
413
+
414
+ expect(el.menuOpened).to.be.false;
415
+ });
416
+ });
417
+ });