@ecl/site-header 5.0.0-alpha.1

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/site-header.js ADDED
@@ -0,0 +1,683 @@
1
+ import { queryOne, queryAll } from '@ecl/dom-utils';
2
+ import { createFocusTrap } from 'focus-trap';
3
+
4
+ /**
5
+ * @param {HTMLElement} element DOM element for component instantiation and scope
6
+ * @param {Object} options
7
+ * @param {String} options.languageLinkSelector
8
+ * @param {String} options.languageListOverlaySelector
9
+ * @param {String} options.languageListEuSelector
10
+ * @param {String} options.languageListNonEuSelector
11
+ * @param {String} options.closeOverlaySelector
12
+ * @param {String} options.searchToggleSelector
13
+ * @param {String} options.searchFormSelector
14
+ * @param {String} options.loginToggleSelector
15
+ * @param {String} options.loginBoxSelector
16
+ * @param {integer} options.tabletBreakpoint
17
+ * @param {Boolean} options.attachClickListener Whether or not to bind click events
18
+ * @param {Boolean} options.attachKeyListener Whether or not to bind keyboard events
19
+ * @param {Boolean} options.attachResizeListener Whether or not to bind resize events
20
+ */
21
+ export class SiteHeader {
22
+ /**
23
+ * @static
24
+ * Shorthand for instance creation and initialisation.
25
+ *
26
+ * @param {HTMLElement} root DOM element for component instantiation and scope
27
+ *
28
+ * @return {SiteHeader} An instance of SiteHeader.
29
+ */
30
+ static autoInit(root, { SITE_HEADER_CORE: defaultOptions = {} } = {}) {
31
+ const siteHeader = new SiteHeader(root, defaultOptions);
32
+ siteHeader.init();
33
+ root.ECLSiteHeader = siteHeader;
34
+ return siteHeader;
35
+ }
36
+
37
+ constructor(
38
+ element,
39
+ {
40
+ containerSelector = '[data-ecl-site-header-top]',
41
+ languageLinkSelector = '[data-ecl-language-selector]',
42
+ languageListOverlaySelector = '[data-ecl-language-list-overlay]',
43
+ languageListEuSelector = '[data-ecl-language-list-eu]',
44
+ languageListNonEuSelector = '[data-ecl-language-list-non-eu]',
45
+ languageListContentSelector = '[data-ecl-language-list-content]',
46
+ closeOverlaySelector = '[data-ecl-language-list-close]',
47
+ searchToggleSelector = '[data-ecl-search-toggle]',
48
+ searchFormSelector = '[data-ecl-search-form]',
49
+ loginToggleSelector = '[data-ecl-login-toggle]',
50
+ loginBoxSelector = '[data-ecl-login-box]',
51
+ notificationSelector = '[data-ecl-site-header-notification]',
52
+ attachClickListener = true,
53
+ attachKeyListener = true,
54
+ attachResizeListener = true,
55
+ tabletBreakpoint = 768,
56
+ } = {},
57
+ ) {
58
+ // Check element
59
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
60
+ throw new TypeError(
61
+ 'DOM element should be given to initialize this widget.',
62
+ );
63
+ }
64
+
65
+ this.element = element;
66
+
67
+ // Options
68
+ this.containerSelector = containerSelector;
69
+ this.languageLinkSelector = languageLinkSelector;
70
+ this.languageListOverlaySelector = languageListOverlaySelector;
71
+ this.languageListEuSelector = languageListEuSelector;
72
+ this.languageListNonEuSelector = languageListNonEuSelector;
73
+ this.languageListContentSelector = languageListContentSelector;
74
+ this.closeOverlaySelector = closeOverlaySelector;
75
+ this.searchToggleSelector = searchToggleSelector;
76
+ this.searchFormSelector = searchFormSelector;
77
+ this.loginToggleSelector = loginToggleSelector;
78
+ this.notificationSelector = notificationSelector;
79
+ this.loginBoxSelector = loginBoxSelector;
80
+ this.attachClickListener = attachClickListener;
81
+ this.attachKeyListener = attachKeyListener;
82
+ this.attachResizeListener = attachResizeListener;
83
+ this.tabletBreakpoint = tabletBreakpoint;
84
+
85
+ // Private variables
86
+ this.languageMaxColumnItems = 8;
87
+ this.languageLink = null;
88
+ this.languageListOverlay = null;
89
+ this.languageListEu = null;
90
+ this.languageListNonEu = null;
91
+ this.languageListContent = null;
92
+ this.close = null;
93
+ this.focusTrap = null;
94
+ this.searchToggle = null;
95
+ this.searchForm = null;
96
+ this.loginToggle = null;
97
+ this.loginBox = null;
98
+ this.resizeTimer = null;
99
+ this.direction = null;
100
+ this.notificationContainer = null;
101
+
102
+ // Bind `this` for use in callbacks
103
+ this.openOverlay = this.openOverlay.bind(this);
104
+ this.closeOverlay = this.closeOverlay.bind(this);
105
+ this.toggleOverlay = this.toggleOverlay.bind(this);
106
+ this.toggleSearch = this.toggleSearch.bind(this);
107
+ this.toggleLogin = this.toggleLogin.bind(this);
108
+ this.setLoginArrow = this.setLoginArrow.bind(this);
109
+ this.setSearchArrow = this.setSearchArrow.bind(this);
110
+ this.handleKeyboardLanguage = this.handleKeyboardLanguage.bind(this);
111
+ this.handleKeyboardGlobal = this.handleKeyboardGlobal.bind(this);
112
+ this.handleClickGlobal = this.handleClickGlobal.bind(this);
113
+ this.handleResize = this.handleResize.bind(this);
114
+ this.setLanguageListHeight = this.setLanguageListHeight.bind(this);
115
+ this.handleNotificationClose = this.handleNotificationClose.bind(this);
116
+ }
117
+
118
+ /**
119
+ * Initialise component.
120
+ */
121
+ init() {
122
+ if (!ECL) {
123
+ throw new TypeError('Called init but ECL is not present');
124
+ }
125
+ ECL.components = ECL.components || new Map();
126
+ this.arrowSize = '0.5rem';
127
+ // Bind global events
128
+ if (this.attachKeyListener) {
129
+ document.addEventListener('keyup', this.handleKeyboardGlobal);
130
+ }
131
+ if (this.attachClickListener) {
132
+ document.addEventListener('click', this.handleClickGlobal);
133
+ }
134
+ if (this.attachResizeListener) {
135
+ window.addEventListener('resize', this.handleResize);
136
+ }
137
+
138
+ // Site header elements
139
+ this.container = queryOne(this.containerSelector);
140
+
141
+ // Language list management
142
+ this.languageLink = queryOne(this.languageLinkSelector);
143
+ this.languageListOverlay = queryOne(this.languageListOverlaySelector);
144
+ this.languageListEu = queryOne(this.languageListEuSelector);
145
+ this.languageListNonEu = queryOne(this.languageListNonEuSelector);
146
+ this.languageListContent = queryOne(this.languageListContentSelector);
147
+ this.close = queryOne(this.closeOverlaySelector);
148
+ this.notification = queryOne(this.notificationSelector);
149
+
150
+ // direction
151
+ this.direction = getComputedStyle(this.element).direction;
152
+ if (this.direction === 'rtl') {
153
+ this.element.classList.add('ecl-site-header--rtl');
154
+ }
155
+
156
+ // Create focus trap
157
+ this.focusTrap = createFocusTrap(this.languageListOverlay, {
158
+ onDeactivate: this.closeOverlay,
159
+ allowOutsideClick: true,
160
+ });
161
+
162
+ if (this.attachClickListener && this.languageLink) {
163
+ this.languageLink.addEventListener('click', this.toggleOverlay);
164
+ }
165
+ if (this.attachClickListener && this.close) {
166
+ this.close.addEventListener('click', this.toggleOverlay);
167
+ }
168
+ if (this.attachKeyListener && this.languageLink) {
169
+ this.languageLink.addEventListener(
170
+ 'keydown',
171
+ this.handleKeyboardLanguage,
172
+ );
173
+ }
174
+
175
+ // Search form management
176
+ this.searchToggle = queryOne(this.searchToggleSelector);
177
+ this.searchForm = queryOne(this.searchFormSelector);
178
+
179
+ if (this.attachClickListener && this.searchToggle) {
180
+ this.searchToggle.addEventListener('click', this.toggleSearch);
181
+ }
182
+
183
+ // Login management
184
+ this.loginToggle = queryOne(this.loginToggleSelector);
185
+ this.loginBox = queryOne(this.loginBoxSelector);
186
+
187
+ if (this.attachClickListener && this.loginToggle) {
188
+ this.loginToggle.addEventListener('click', this.toggleLogin);
189
+ }
190
+
191
+ // Set ecl initialized attribute
192
+ this.element.setAttribute('data-ecl-auto-initialized', 'true');
193
+ ECL.components.set(this.element, this);
194
+
195
+ if (this.notification) {
196
+ this.notificationContainer = this.notification.closest(
197
+ '.ecl-site-header__notification',
198
+ );
199
+
200
+ setTimeout(() => {
201
+ const eclNotification = ECL.components.get(this.notification);
202
+
203
+ if (eclNotification) {
204
+ eclNotification.on('onClose', this.handleNotificationClose);
205
+ }
206
+ }, 0);
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Destroy component.
212
+ */
213
+ destroy() {
214
+ if (this.attachClickListener && this.languageLink) {
215
+ this.languageLink.removeEventListener('click', this.toggleOverlay);
216
+ }
217
+ if (this.focusTrap) {
218
+ this.focusTrap.deactivate();
219
+ }
220
+
221
+ if (this.attachKeyListener && this.languageLink) {
222
+ this.languageLink.removeEventListener(
223
+ 'keydown',
224
+ this.handleKeyboardLanguage,
225
+ );
226
+ }
227
+
228
+ if (this.attachClickListener && this.close) {
229
+ this.close.removeEventListener('click', this.toggleOverlay);
230
+ }
231
+
232
+ if (this.attachClickListener && this.searchToggle) {
233
+ this.searchToggle.removeEventListener('click', this.toggleSearch);
234
+ }
235
+
236
+ if (this.attachClickListener && this.loginToggle) {
237
+ this.loginToggle.removeEventListener('click', this.toggleLogin);
238
+ }
239
+
240
+ if (this.attachKeyListener) {
241
+ document.removeEventListener('keyup', this.handleKeyboardGlobal);
242
+ }
243
+
244
+ if (this.attachClickListener) {
245
+ document.removeEventListener('click', this.handleClickGlobal);
246
+ }
247
+
248
+ if (this.attachResizeListener) {
249
+ window.removeEventListener('resize', this.handleResize);
250
+ }
251
+
252
+ if (this.element) {
253
+ this.element.removeAttribute('data-ecl-auto-initialized');
254
+ this.element.classList.remove('ecl-site-header--rtl');
255
+ ECL.components.delete(this.element);
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Update display of the modal language list overlay.
261
+ */
262
+ updateOverlay() {
263
+ // Check number of items and adapt display
264
+ let columnsEu = 1;
265
+ let columnsNonEu = 1;
266
+ if (this.languageListEu) {
267
+ // Get all Eu languages
268
+ const itemsEu = queryAll(
269
+ '.ecl-site-header__language-item',
270
+ this.languageListEu,
271
+ );
272
+
273
+ // Calculate number of columns
274
+ columnsEu = Math.ceil(itemsEu.length / this.languageMaxColumnItems);
275
+
276
+ // Apply column display
277
+ if (columnsEu > 1) {
278
+ this.languageListEu.classList.add(
279
+ `ecl-site-header__language-category--${columnsEu}-col`,
280
+ );
281
+ }
282
+ }
283
+ if (this.languageListNonEu) {
284
+ // Get all non-Eu languages
285
+ const itemsNonEu = queryAll(
286
+ '.ecl-site-header__language-item',
287
+ this.languageListNonEu,
288
+ );
289
+
290
+ // Calculate number of columns
291
+ columnsNonEu = Math.ceil(itemsNonEu.length / this.languageMaxColumnItems);
292
+
293
+ // Apply column display
294
+ if (columnsNonEu > 1) {
295
+ this.languageListNonEu.classList.add(
296
+ `ecl-site-header__language-category--${columnsNonEu}-col`,
297
+ );
298
+ }
299
+ }
300
+
301
+ // Check total width, and change display if needed
302
+ if (this.languageListEu) {
303
+ this.languageListEu.parentNode.classList.remove(
304
+ 'ecl-site-header__language-content--stack',
305
+ );
306
+ } else if (this.languageListNonEu) {
307
+ this.languageListNonEu.parentNode.classList.remove(
308
+ 'ecl-site-header__language-content--stack',
309
+ );
310
+ }
311
+ let popoverRect = this.languageListOverlay.getBoundingClientRect();
312
+ const containerRect = this.container.getBoundingClientRect();
313
+
314
+ if (popoverRect.width > containerRect.width) {
315
+ // Stack elements
316
+ if (this.languageListEu) {
317
+ this.languageListEu.parentNode.classList.add(
318
+ 'ecl-site-header__language-content--stack',
319
+ );
320
+ } else if (this.languageListNonEu) {
321
+ this.languageListNonEu.parentNode.classList.add(
322
+ 'ecl-site-header__language-content--stack',
323
+ );
324
+ }
325
+
326
+ // Adapt column display
327
+ if (this.languageListNonEu) {
328
+ this.languageListNonEu.classList.remove(
329
+ `ecl-site-header__language-category--${columnsNonEu}-col`,
330
+ );
331
+ this.languageListNonEu.classList.add(
332
+ `ecl-site-header__language-category--${Math.max(
333
+ columnsEu,
334
+ columnsNonEu,
335
+ )}-col`,
336
+ );
337
+ }
338
+ }
339
+
340
+ // Check available space
341
+ this.languageListOverlay.classList.remove(
342
+ 'ecl-site-header__language-container--push-right',
343
+ 'ecl-site-header__language-container--push-left',
344
+ );
345
+ this.languageListOverlay.classList.remove(
346
+ 'ecl-site-header__language-container--full',
347
+ );
348
+ this.languageListOverlay.style.removeProperty(
349
+ '--ecl-language-arrow-position',
350
+ );
351
+ this.languageListOverlay.style.removeProperty('right');
352
+ this.languageListOverlay.style.removeProperty('left');
353
+
354
+ popoverRect = this.languageListOverlay.getBoundingClientRect();
355
+ const screenWidth = window.innerWidth;
356
+ const linkRect = this.languageLink.getBoundingClientRect();
357
+ // Popover too large
358
+ if (this.direction === 'ltr' && popoverRect.right > screenWidth) {
359
+ // Push the popover to the right
360
+ this.languageListOverlay.classList.add(
361
+ 'ecl-site-header__language-container--push-right',
362
+ );
363
+ this.languageListOverlay.style.setProperty(
364
+ 'right',
365
+ `calc(-${containerRect.right}px + ${linkRect.right}px)`,
366
+ );
367
+ // Adapt arrow position
368
+ const arrowPosition =
369
+ containerRect.right - linkRect.right + linkRect.width / 2;
370
+ this.languageListOverlay.style.setProperty(
371
+ '--ecl-language-arrow-position',
372
+ `calc(${arrowPosition}px - ${this.arrowSize})`,
373
+ );
374
+ } else if (this.direction === 'rtl' && popoverRect.left < 0) {
375
+ this.languageListOverlay.classList.add(
376
+ 'ecl-site-header__language-container--push-left',
377
+ );
378
+ this.languageListOverlay.style.setProperty(
379
+ 'left',
380
+ `calc(-${linkRect.left}px + ${containerRect.left}px)`,
381
+ );
382
+ // Adapt arrow position
383
+ const arrowPosition =
384
+ linkRect.right - containerRect.left - linkRect.width / 2;
385
+ this.languageListOverlay.style.setProperty(
386
+ '--ecl-language-arrow-position',
387
+ `${arrowPosition}px`,
388
+ );
389
+ }
390
+
391
+ // Mobile popover (full width)
392
+ if (window.innerWidth < this.tabletBreakpoint) {
393
+ // Push the popover to the right
394
+ this.languageListOverlay.classList.add(
395
+ 'ecl-site-header__language-container--full',
396
+ );
397
+ this.languageListOverlay.style.removeProperty('right');
398
+
399
+ // Adapt arrow position
400
+ const arrowPosition =
401
+ popoverRect.right - linkRect.right + linkRect.width / 2;
402
+ this.languageListOverlay.style.setProperty(
403
+ '--ecl-language-arrow-position',
404
+ `calc(${arrowPosition}px - ${this.arrowSize})`,
405
+ );
406
+ }
407
+
408
+ if (
409
+ this.loginBox &&
410
+ this.loginBox.classList.contains('ecl-site-header__login-box--active')
411
+ ) {
412
+ this.setLoginArrow();
413
+ }
414
+ if (
415
+ this.searchForm &&
416
+ this.searchForm.classList.contains('ecl-site-header__search--active')
417
+ ) {
418
+ this.setSearchArrow();
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Removes the containers of the notification element
424
+ */
425
+ handleNotificationClose() {
426
+ if (this.notificationContainer) {
427
+ this.notificationContainer.remove();
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Set a max height for the language list content
433
+ */
434
+ setLanguageListHeight() {
435
+ const viewportHeight = window.innerHeight;
436
+
437
+ if (this.languageListContent) {
438
+ const listTop = this.languageListContent.getBoundingClientRect().top;
439
+
440
+ const availableSpace = viewportHeight - listTop;
441
+ if (availableSpace > 0) {
442
+ this.languageListContent.style.maxHeight = `${availableSpace}px`;
443
+ }
444
+ }
445
+ }
446
+
447
+ /**
448
+ * Shows the modal language list overlay.
449
+ */
450
+ openOverlay() {
451
+ // Display language list
452
+ this.languageListOverlay.hidden = false;
453
+ this.languageListOverlay.setAttribute('aria-modal', 'true');
454
+ this.languageLink.setAttribute('aria-expanded', 'true');
455
+ this.setLanguageListHeight();
456
+ }
457
+
458
+ /**
459
+ * Hides the modal language list overlay.
460
+ */
461
+ closeOverlay() {
462
+ this.languageListOverlay.hidden = true;
463
+ this.languageListOverlay.removeAttribute('aria-modal');
464
+ this.languageLink.setAttribute('aria-expanded', 'false');
465
+ }
466
+
467
+ /**
468
+ * Toggles the modal language list overlay.
469
+ *
470
+ * @param {Event} e
471
+ */
472
+ toggleOverlay(e) {
473
+ if (!this.languageListOverlay || !this.focusTrap) return;
474
+
475
+ e.preventDefault();
476
+
477
+ if (this.languageListOverlay.hasAttribute('hidden')) {
478
+ this.openOverlay();
479
+ this.updateOverlay();
480
+ this.focusTrap.activate();
481
+ } else {
482
+ this.focusTrap.deactivate();
483
+ }
484
+ }
485
+
486
+ /**
487
+ * Trigger events on resize
488
+ * Uses a debounce, for performance
489
+ */
490
+ handleResize() {
491
+ if (
492
+ !this.languageListOverlay ||
493
+ this.languageListOverlay.hasAttribute('hidden')
494
+ )
495
+ return;
496
+ if (
497
+ (this.loginBox &&
498
+ this.loginBox.classList.contains(
499
+ 'ecl-site-header__login-box--active',
500
+ )) ||
501
+ (this.searchForm &&
502
+ this.searchForm.classList.contains('ecl-site-header__search--active'))
503
+ ) {
504
+ clearTimeout(this.resizeTimer);
505
+ this.resizeTimer = setTimeout(() => {
506
+ this.updateOverlay();
507
+ }, 200);
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Handles keyboard events specific to the language list.
513
+ *
514
+ * @param {Event} e
515
+ */
516
+ handleKeyboardLanguage(e) {
517
+ // Open the menu with space and enter
518
+ if (e.keyCode === 32 || e.key === 'Enter') {
519
+ this.toggleOverlay(e);
520
+ }
521
+ }
522
+
523
+ /**
524
+ * Toggles the search form.
525
+ *
526
+ * @param {Event} e
527
+ */
528
+ toggleSearch(e) {
529
+ if (!this.searchForm) return;
530
+
531
+ e.preventDefault();
532
+
533
+ // Get current status
534
+ const isExpanded =
535
+ this.searchToggle.getAttribute('aria-expanded') === 'true';
536
+
537
+ // Close other boxes
538
+ if (
539
+ this.loginToggle &&
540
+ this.loginToggle.getAttribute('aria-expanded') === 'true'
541
+ ) {
542
+ this.toggleLogin(e);
543
+ }
544
+
545
+ // Toggle the search form
546
+ this.searchToggle.setAttribute(
547
+ 'aria-expanded',
548
+ isExpanded ? 'false' : 'true',
549
+ );
550
+
551
+ if (!isExpanded) {
552
+ this.searchForm.classList.add('ecl-site-header__search--active');
553
+ this.setSearchArrow();
554
+ } else {
555
+ this.searchForm.classList.remove('ecl-site-header__search--active');
556
+ }
557
+ }
558
+
559
+ setLoginArrow() {
560
+ const loginRect = this.loginBox.getBoundingClientRect();
561
+ if (loginRect.x === 0) {
562
+ const loginToggleRect = this.loginToggle.getBoundingClientRect();
563
+ const arrowPosition =
564
+ window.innerWidth - loginToggleRect.right + loginToggleRect.width / 2;
565
+
566
+ this.loginBox.style.setProperty(
567
+ '--ecl-login-arrow-position',
568
+ `calc(${arrowPosition}px - ${this.arrowSize})`,
569
+ );
570
+ }
571
+ }
572
+
573
+ setSearchArrow() {
574
+ const searchRect = this.searchForm.getBoundingClientRect();
575
+ if (searchRect.x === 0) {
576
+ const searchToggleRect = this.searchToggle.getBoundingClientRect();
577
+ const arrowPosition =
578
+ window.innerWidth - searchToggleRect.right + searchToggleRect.width / 2;
579
+
580
+ this.searchForm.style.setProperty(
581
+ '--ecl-search-arrow-position',
582
+ `calc(${arrowPosition}px - ${this.arrowSize})`,
583
+ );
584
+ }
585
+ }
586
+
587
+ /**
588
+ * Toggles the login form.
589
+ *
590
+ * @param {Event} e
591
+ */
592
+ toggleLogin(e) {
593
+ if (!this.loginBox) return;
594
+
595
+ e.preventDefault();
596
+
597
+ // Get current status
598
+ const isExpanded =
599
+ this.loginToggle.getAttribute('aria-expanded') === 'true';
600
+
601
+ // Close other boxes
602
+ if (
603
+ this.searchToggle &&
604
+ this.searchToggle.getAttribute('aria-expanded') === 'true'
605
+ ) {
606
+ this.toggleSearch(e);
607
+ }
608
+
609
+ // Toggle the login box
610
+ this.loginToggle.setAttribute(
611
+ 'aria-expanded',
612
+ isExpanded ? 'false' : 'true',
613
+ );
614
+ if (!isExpanded) {
615
+ this.loginBox.classList.add('ecl-site-header__login-box--active');
616
+ this.setLoginArrow();
617
+ } else {
618
+ this.loginBox.classList.remove('ecl-site-header__login-box--active');
619
+ }
620
+ }
621
+
622
+ /**
623
+ * Handles global keyboard events, triggered outside of the site header.
624
+ *
625
+ * @param {Event} e
626
+ */
627
+ handleKeyboardGlobal(e) {
628
+ if (!this.languageLink) return;
629
+ const listExpanded = this.languageLink.getAttribute('aria-expanded');
630
+
631
+ // Detect press on Escape
632
+ if (e.key === 'Escape' || e.key === 'Esc') {
633
+ if (listExpanded === 'true') {
634
+ this.toggleOverlay(e);
635
+ }
636
+ }
637
+ }
638
+
639
+ /**
640
+ * Handles global click events, triggered outside of the site header.
641
+ *
642
+ * @param {Event} e
643
+ */
644
+ handleClickGlobal(e) {
645
+ if (!this.languageLink && !this.searchToggle && !this.loginToggle) return;
646
+ const listExpanded =
647
+ this.languageLink && this.languageLink.getAttribute('aria-expanded');
648
+ const loginExpanded =
649
+ this.loginToggle &&
650
+ this.loginToggle.getAttribute('aria-expanded') === 'true';
651
+ const searchExpanded =
652
+ this.searchToggle &&
653
+ this.searchToggle.getAttribute('aria-expanded') === 'true';
654
+ // Check if the language list is open
655
+ if (listExpanded === 'true') {
656
+ // Check if the click occured in the language popover
657
+ if (
658
+ !this.languageListOverlay.contains(e.target) &&
659
+ !this.languageLink.contains(e.target)
660
+ ) {
661
+ this.toggleOverlay(e);
662
+ }
663
+ }
664
+ if (loginExpanded) {
665
+ if (
666
+ !this.loginBox.contains(e.target) &&
667
+ !this.loginToggle.contains(e.target)
668
+ ) {
669
+ this.toggleLogin(e);
670
+ }
671
+ }
672
+ if (searchExpanded) {
673
+ if (
674
+ !this.searchForm.contains(e.target) &&
675
+ !this.searchToggle.contains(e.target)
676
+ ) {
677
+ this.toggleSearch(e);
678
+ }
679
+ }
680
+ }
681
+ }
682
+
683
+ export default SiteHeader;