@iamproperty/components 7.6.4--beta2 → 7.6.4--beta3

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 (110) hide show
  1. package/assets/css/components/actionbar.component.css +1 -1
  2. package/assets/css/components/actionbar.component.css.map +1 -1
  3. package/assets/css/components/address-lookup.component.css +1 -1
  4. package/assets/css/components/address-lookup.component.css.map +1 -1
  5. package/assets/css/components/calendar.component.css +1 -1
  6. package/assets/css/components/calendar.component.css.map +1 -1
  7. package/assets/css/components/fileupload.css +1 -1
  8. package/assets/css/components/fileupload.css.map +1 -1
  9. package/assets/css/components/multiselect.css +1 -1
  10. package/assets/css/components/multiselect.css.map +1 -1
  11. package/assets/css/components/multiselect.preload.css +1 -1
  12. package/assets/css/components/multiselect.preload.css.map +1 -1
  13. package/assets/css/components/nav.component.css +1 -1
  14. package/assets/css/components/nav.component.css.map +1 -1
  15. package/assets/css/components/pagination.css +1 -1
  16. package/assets/css/components/pagination.css.map +1 -1
  17. package/assets/css/components/slider.css +1 -1
  18. package/assets/css/components/slider.css.map +1 -1
  19. package/assets/css/components/tag.component.css +1 -1
  20. package/assets/css/components/tag.component.css.map +1 -1
  21. package/assets/css/components/tag.preload.css +1 -1
  22. package/assets/css/components/tag.preload.css.map +1 -1
  23. package/assets/css/core.min.css +1 -1
  24. package/assets/css/core.min.css.map +1 -1
  25. package/assets/css/style.min.css +1 -1
  26. package/assets/css/style.min.css.map +1 -1
  27. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  28. package/assets/js/components/actionbar/actionbar.component.min.js +2 -2
  29. package/assets/js/components/address-lookup/address-lookup.component.js +11 -5
  30. package/assets/js/components/address-lookup/address-lookup.component.min.js +4 -4
  31. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
  32. package/assets/js/components/advanced-select/advanced-select.component.min.js +1 -1
  33. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  34. package/assets/js/components/barchart/barchart.component.min.js +1 -1
  35. package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
  36. package/assets/js/components/calendar/calendar.component.min.js +2 -2
  37. package/assets/js/components/card/card.component.min.js +1 -1
  38. package/assets/js/components/carousel/carousel.component.min.js +1 -1
  39. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  40. package/assets/js/components/content/content.component.min.js +1 -1
  41. package/assets/js/components/darkmode/darkmode.component.min.js +1 -1
  42. package/assets/js/components/doughnutchart/doughnutchart.component.min.js +1 -1
  43. package/assets/js/components/fileupload/fileupload.component.min.js +4 -4
  44. package/assets/js/components/filter-card/filter-card.component.min.js +1 -1
  45. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  46. package/assets/js/components/form/form.component.min.js +1 -1
  47. package/assets/js/components/header/header.component.min.js +1 -1
  48. package/assets/js/components/inline-edit/inline-edit.component.min.js +1 -1
  49. package/assets/js/components/input/input.component.min.js +1 -1
  50. package/assets/js/components/input-range/input-range.component.min.js +1 -1
  51. package/assets/js/components/marketing/marketing.component.min.js +1 -1
  52. package/assets/js/components/menu/menu.component.min.js +1 -1
  53. package/assets/js/components/milestone/milestone.component.min.js +1 -1
  54. package/assets/js/components/milestone-group/milestone-group.component.min.js +1 -1
  55. package/assets/js/components/modal/modal.component.js +1 -1
  56. package/assets/js/components/modal/modal.component.min.js +2 -2
  57. package/assets/js/components/modal/modal.component.min.js.map +1 -1
  58. package/assets/js/components/multi-step/multi-step.component.min.js +1 -1
  59. package/assets/js/components/multi-step-modal/multi-step-modal.component.min.js +1 -1
  60. package/assets/js/components/multiselect/multiselect.component.js +9 -76
  61. package/assets/js/components/multiselect/multiselect.component.min.js +4 -4
  62. package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -1
  63. package/assets/js/components/nav/nav.component.min.js +2 -2
  64. package/assets/js/components/notification/notification.component.min.js +1 -1
  65. package/assets/js/components/pagination/pagination.component.min.js +2 -2
  66. package/assets/js/components/password/password.component.min.js +1 -1
  67. package/assets/js/components/popover/popover.component.min.js +1 -1
  68. package/assets/js/components/rank/rank.component.min.js +1 -1
  69. package/assets/js/components/rankings/rankings.component.min.js +1 -1
  70. package/assets/js/components/rating/rating.component.min.js +1 -1
  71. package/assets/js/components/record-card/record-card.component.min.js +1 -1
  72. package/assets/js/components/search/search.component.min.js +1 -1
  73. package/assets/js/components/slider/slider.component.min.js +2 -2
  74. package/assets/js/components/split-button/split-button.component.min.js +1 -1
  75. package/assets/js/components/std-address-lookup/std-address-lookup.component.js +39 -2
  76. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js +10 -9
  77. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js.map +1 -1
  78. package/assets/js/components/table/table.component.min.js +1 -1
  79. package/assets/js/components/table-ajax/table-ajax.component.min.js +1 -1
  80. package/assets/js/components/table-basic/table-basic.component.min.js +1 -1
  81. package/assets/js/components/table-no-submit/table-no-submit.component.min.js +1 -1
  82. package/assets/js/components/table-submit/table-submit.component.min.js +1 -1
  83. package/assets/js/components/tabs/tabs.component.min.js +1 -1
  84. package/assets/js/components/tag/tag.component.js +6 -1
  85. package/assets/js/components/tag/tag.component.min.js +4 -4
  86. package/assets/js/components/tag/tag.component.min.js.map +1 -1
  87. package/assets/js/components/tooltip/tooltip.component.min.js +1 -1
  88. package/assets/js/components/video-card/video-card.component.min.js +1 -1
  89. package/assets/js/components/video-modal/video-modal.component.min.js +1 -1
  90. package/assets/js/components/word-count/word-count.component.min.js +1 -1
  91. package/assets/js/modules/dropdown.js +97 -4
  92. package/assets/js/scripts.bundle.js +1 -1
  93. package/assets/js/scripts.bundle.min.js +1 -1
  94. package/assets/sass/_components.scss +0 -2
  95. package/assets/sass/_elements.scss +1 -0
  96. package/assets/sass/components/multiselect.preload.scss +0 -55
  97. package/assets/sass/components/multiselect.scss +172 -174
  98. package/assets/sass/components/tag.component.scss +38 -57
  99. package/assets/sass/components/tag.preload.scss +1 -26
  100. package/assets/sass/elements/dropdown.scss +87 -0
  101. package/assets/sass/elements/forms.scss +6 -0
  102. package/assets/ts/components/address-lookup/address-lookup.component.ts +12 -5
  103. package/assets/ts/components/modal/modal.component.ts +1 -1
  104. package/assets/ts/components/multiselect/multiselect.component.ts +10 -78
  105. package/assets/ts/components/std-address-lookup/std-address-lookup.component.ts +51 -2
  106. package/assets/ts/components/tag/tag.component.ts +8 -11
  107. package/assets/ts/modules/dropdown.ts +117 -5
  108. package/dist/components.es.js +28 -28
  109. package/dist/components.umd.js +219 -212
  110. package/package.json +2 -2
@@ -1,5 +1,4 @@
1
- import Cookies from 'js-cookie';
2
- import { filterList } from '../../modules/dropdown';
1
+ import { searchAjax, filterList, addKeyboardEvents } from '../../modules/dropdown';
3
2
 
4
3
  // Data layer Web component created
5
4
  window.dataLayer = window.dataLayer || [];
@@ -56,6 +55,12 @@ class iamMultiselect extends HTMLElement {
56
55
  const ajaxURL = this.getAttribute('data-url');
57
56
  innerLabel.innerHTML = multiselect.getAttribute('data-label');
58
57
 
58
+ // Make sure the dropdown options are set
59
+ Array.from(this.querySelectorAll(':scope > label')).forEach((label) => {
60
+ label.classList.add('dropdown__option');
61
+ label?.querySelector('i')?.remove();
62
+ });
63
+
59
64
  if (multiselect.hasAttribute('placeholder')) {
60
65
  search.setAttribute('placeholder', multiselect.getAttribute('placeholder'));
61
66
  }
@@ -132,7 +137,7 @@ class iamMultiselect extends HTMLElement {
132
137
  if (multiselect.hasAttribute('data-url')) {
133
138
 
134
139
  if (search.value.length == 3) {
135
- searchAjax(search.value);
140
+ searchAjax(multiselect, search, filterList);
136
141
  }
137
142
  } else {
138
143
 
@@ -222,6 +227,7 @@ class iamMultiselect extends HTMLElement {
222
227
  });
223
228
 
224
229
  // Add some keyboard features to keep it accessible
230
+ addKeyboardEvents(this, search);
225
231
  multiselect.addEventListener('keydown', function (event) {
226
232
  const activeElement = document.activeElement;
227
233
 
@@ -262,38 +268,6 @@ class iamMultiselect extends HTMLElement {
262
268
  if (nextCheckbox) nextCheckbox.focus();
263
269
  else search.focus();
264
270
  }
265
- break;
266
- case 'ArrowUp':
267
- // Up pressed
268
- event.preventDefault();
269
-
270
- if (activeElement.hasAttribute('type') && activeElement.getAttribute('type') == 'checkbox') {
271
- const arrCheckboxes = multiselect.querySelectorAll(`label:not([slot="checked"]):not([slot="checked"])`);
272
-
273
- const activeIndex = Array.from(arrCheckboxes).indexOf(activeElement.closest('label'));
274
- const prevCheckbox = Array.from(arrCheckboxes)[activeIndex - 1];
275
-
276
- if (prevCheckbox) prevCheckbox.focus();
277
- else search.focus();
278
- }
279
-
280
- break;
281
- case 'ArrowDown':
282
- // Down pressed
283
- event.preventDefault();
284
-
285
- if (activeElement == multiselect) {
286
- multiselect.querySelector('label:not([slot="checked"]):not([slot="checked"])').focus();
287
- } else if (activeElement.hasAttribute('type') && activeElement.getAttribute('type') == 'checkbox') {
288
- const activeValue = activeElement.value;
289
-
290
- const nextCheckbox = multiselect.querySelector(
291
- `label:has(input[value="${activeValue}"]) ~ label:not([slot="checked"]):not([slot="checked"])`
292
- );
293
-
294
- if (nextCheckbox) nextCheckbox.focus();
295
- }
296
-
297
271
  break;
298
272
  case 'Enter':
299
273
  event.stopPropagation();
@@ -318,6 +292,7 @@ class iamMultiselect extends HTMLElement {
318
292
  }
319
293
  });
320
294
 
295
+
321
296
  function checkLastTag(): Element | null {
322
297
  if (order == 0) return false;
323
298
 
@@ -368,49 +343,6 @@ class iamMultiselect extends HTMLElement {
368
343
  wrapper.removeAttribute('data-mousedown');
369
344
  });
370
345
 
371
- const searchAjax = async (searchterm): any => {
372
- const searchAjaxURL = `${ajaxURL}${encodeURI(searchterm)}`;
373
-
374
- // Setup controller vars if not already set
375
- if (!window.controller) window.controller = [];
376
-
377
- // Abort if controller already present for this url
378
- if (window.controller[searchAjaxURL]) window.controller[searchAjaxURL].abort();
379
-
380
- // Create a new controller so it can be aborted if new fetch made
381
- window.controller[searchAjaxURL] = new AbortController();
382
- const { signal } = controller[searchAjaxURL];
383
-
384
- try {
385
- await fetch(searchAjaxURL, {
386
- signal: signal,
387
- method: 'get',
388
- credentials: 'same-origin',
389
- headers: new Headers({
390
- 'Content-Type': 'application/json',
391
- Accept: 'application/json',
392
- 'X-Requested-With': 'XMLHttpRequest',
393
- 'X-XSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
394
- }),
395
- })
396
- .then((response) => response.json())
397
- .then((response) => {
398
-
399
- let items = '';
400
-
401
- for (let i = 0; i < response['data'].length; i++) {
402
- items += `<label class="tag"><input type="checkbox" name="${multiselect.hasAttribute('data-name') ? multiselect.getAttribute('data-name') : 'tags'}" value="${ response['data'][i].value }"/>${ response['data'][i].title }</label>`;
403
- }
404
-
405
- multiselect.insertAdjacentHTML('beforeend', `${items}`);
406
-
407
- filterList(multiselect, search);
408
- return response;
409
- });
410
- } catch (error) {
411
- console.log(error);
412
- }
413
- };
414
346
  }
415
347
  }
416
348
 
@@ -1556,7 +1556,7 @@ class iamSTDAddressLookup extends HTMLElement {
1556
1556
  data-min-chars="5"
1557
1557
  ${this.hasAttribute('data-title') ? `data-title='${this.getAttribute('data-title')}'` : `data-title='Find an address by postcode'`}
1558
1558
  data-placeholder="UK, Isle of Man, & Channel Islands "
1559
- ${this.hasAttribute('data-manual') ? 'data-manual' : ''}
1559
+ ${this.hasAttribute('data-manual') ? 'data-manual' : ''}
1560
1560
  ${this.hasAttribute('data-allow-manual') ? 'data-allow-manual' : ''}
1561
1561
  ${this.hasAttribute('data-use') ? `data-use='${this.getAttribute('data-use')}'` : ''}
1562
1562
  ${this.hasAttribute('data-use-label') ? `data-use-label='${this.getAttribute('data-use-label')}'` : ''}
@@ -1568,6 +1568,7 @@ class iamSTDAddressLookup extends HTMLElement {
1568
1568
  ${this.hasAttribute('data-force-manual') ? `data-force-manual` : ''}
1569
1569
  ${this.hasAttribute('data-matched') ? `data-matched='${this.getAttribute('data-matched')}'` : ''}
1570
1570
  ${this.hasAttribute('data-matched-label') ? `data-matched-label='${this.getAttribute('data-matched-label')}'` : ''}
1571
+ ${this.hasAttribute('data-disabled') ? 'data-disabled="disabled"' : ''}
1571
1572
  data-postcode-lookup-label="Back to UK postcode lookup">
1572
1573
 
1573
1574
  <p class="hint pb-2 d-block" slot="hint">Unsure of the postcode? Check with the <a href="https://www.royalmail.com/find-a-postcode" target="_blank"><i class="fa-regular fa-arrow-up-right-from-square"></i>Royal Mail address finder</a></p>
@@ -1661,7 +1662,7 @@ class iamSTDAddressLookup extends HTMLElement {
1661
1662
  </fieldset>
1662
1663
 
1663
1664
  <button slot="actions" type="button" id="overseasToggle" class="link toggleOverseas">Use overseas address</button>` : ''}
1664
- ${this.hasAttribute('data-address-unknown') ? `<label slot="actions"><input type="checkbox" value="true" name="${this.getAttribute('data-address-unknown')}" ${this.hasAttribute('data-address-unknown-checked') ? 'checked="checked"' : '' }/> Address unknown</label>` : ``}
1665
+ ${this.hasAttribute('data-address-unknown') ? `<label slot="actions" id="address_unknown_checkbox"><input type="checkbox" value="true" name="${this.getAttribute('data-address-unknown')}" ${this.hasAttribute('data-address-unknown-checked') ? 'checked="checked"' : '' }/> Address unknown</label>` : ``}
1665
1666
  <div class="bg-light text-center px-3" slot="afterList">
1666
1667
  <p class="p-2">Can't find an address? Check details with the <br/><a href="" class="fa-new"><i class="fa-regular fa-arrow-up-right-from-square"></i>Royal mail address finder</a></p>
1667
1668
  ${this.hasAttribute('data-allow-overseas') ? `<hr/><p class="p-2">If the address doesn’t exist you can enter manually <br /><button type="button" id="overseasToggleInline" class="mt-1 mb-0 btn btn-action"><i class="fa-regular fa-edit me-1"></i>Enter address manually</button></p>` : ''}
@@ -1678,6 +1679,7 @@ class iamSTDAddressLookup extends HTMLElement {
1678
1679
  const languageToggle = this.querySelector('#languageToggle');
1679
1680
  const atleastone = this.querySelector('.overseas-atleastone');
1680
1681
  const overseasFields = this.querySelector('.overseas');
1682
+ const addressUnknownCheckbox = this.querySelector('#address_unknown_checkbox input');
1681
1683
 
1682
1684
  const openOverseas = (): void => {
1683
1685
  const updateEvent = new CustomEvent('open-manual');
@@ -1818,6 +1820,53 @@ class iamSTDAddressLookup extends HTMLElement {
1818
1820
  }
1819
1821
  }
1820
1822
 
1823
+
1824
+ // Addres unknown
1825
+
1826
+ const toggleAddressFields = () => {
1827
+
1828
+
1829
+ if(addressUnknownCheckbox.checked){
1830
+ Array.from(this.querySelectorAll('input:not([name="address-unknown"]), select')).forEach((input) => {
1831
+
1832
+ input.setAttribute('disabled','disabled');
1833
+ input.setAttribute('data-unknown-disabled','true');
1834
+
1835
+ addressComponent.setAttribute('data-disabled','disabled');
1836
+ });
1837
+ }
1838
+ else {
1839
+ Array.from(this.querySelectorAll('[data-unknown-disabled]')).forEach((input) => {
1840
+
1841
+ addressComponent.removeAttribute('data-disabled','disabled');
1842
+ input.removeAttribute('disabled');
1843
+ input.removeAttribute('data-unknown-disabled');
1844
+ });
1845
+ }
1846
+ }
1847
+ toggleAddressFields();
1848
+
1849
+ addressUnknownCheckbox?.addEventListener('change', (e) => {
1850
+
1851
+ toggleAddressFields();
1852
+ });
1853
+ }
1854
+
1855
+ static get observedAttributes(): any {
1856
+ return ['data-url'];
1857
+ }
1858
+
1859
+ attributeChangedCallback(attrName, oldVal, newVal): void {
1860
+ const addressComponent = this.querySelector('iam-address-lookup');
1861
+
1862
+ switch (attrName) {
1863
+ case 'data-url': {
1864
+ if (oldVal != newVal && addressComponent) {
1865
+ addressComponent.setAttribute('data-url', newVal + '?search_string=');
1866
+ }
1867
+ break;
1868
+ }
1869
+ }
1821
1870
  }
1822
1871
  }
1823
1872
 
@@ -1,5 +1,5 @@
1
1
  import { trackComponent, trackComponentRegistered } from '../_global';
2
- import { searchAjax, filterList, setTag } from '../../modules/dropdown';
2
+ import { searchAjax, filterList, setTag, addKeyboardEvents } from '../../modules/dropdown';
3
3
 
4
4
  trackComponentRegistered('iam-tag');
5
5
 
@@ -38,10 +38,14 @@ class iamTag extends HTMLElement {
38
38
  const input = this.querySelector(':checked');
39
39
  const inputName = input?.getAttribute('name');
40
40
  let tag = this.querySelector('label:has(:checked)');
41
-
42
41
  setTag(tag);
43
-
44
42
 
43
+ // Make sure the dropdown options are set
44
+ Array.from(this.querySelectorAll(':scope > label')).forEach((label) => {
45
+ label.classList.add('dropdown__option');
46
+ });
47
+
48
+
45
49
  this.addEventListener('click',()=>{
46
50
  if (event && event.target instanceof HTMLElement && event.target.closest('label:has(:checked)')) {
47
51
 
@@ -62,8 +66,6 @@ class iamTag extends HTMLElement {
62
66
  }
63
67
  });
64
68
 
65
-
66
-
67
69
  this.addEventListener('change', (event) => {
68
70
  if (event && event.target instanceof HTMLElement && event.target.closest('input[type="radio"],input[type="checkbox"]')) {
69
71
  const checkbox = event.target.closest('input[type="radio"],input[type="checkbox"]');
@@ -94,13 +96,8 @@ class iamTag extends HTMLElement {
94
96
  }
95
97
  });
96
98
 
97
-
98
-
99
99
  // TODO Add keyboard actions
100
-
101
-
102
-
103
-
100
+ addKeyboardEvents(this, search);
104
101
  }
105
102
  }
106
103
 
@@ -1,4 +1,4 @@
1
- import Cookies from 'js-cookie';
1
+ import Cookies from '../../../node_modules/js-cookie/dist/js.cookie.mjs';
2
2
 
3
3
  export const filterList = (component, search): void => {
4
4
 
@@ -27,8 +27,11 @@ export const searchAjax = async (component, search, callback): any => {
27
27
 
28
28
  console.log(firstInput);
29
29
 
30
- const inputType = firstInput.getAttribute('type');
31
- const inputName = firstInput.getAttribute('name');
30
+ const inputType = firstInput && firstInput.hasAttribute('type') ? firstInput.getAttribute('type') : 'checkbox';
31
+ let inputName = firstInput && firstInput.hasAttribute('name') ? firstInput.getAttribute('name') : 'tags';
32
+
33
+ if(component.hasAttribute('data-name'))
34
+ inputName = component.hasAttribute('data-name');
32
35
 
33
36
  const searchAjaxURL = `${ajaxURL}?search_query=${encodeURI(searchterm)}`;
34
37
 
@@ -62,7 +65,7 @@ export const searchAjax = async (component, search, callback): any => {
62
65
  for (let i = 0; i < response['data'].length; i++) {
63
66
 
64
67
  if(!component.querySelector(`[value="${response['data'][i].value}"]`))
65
- items += `<label class="tag"><input type="${inputType}" name="${component.hasAttribute('data-name') ? component.getAttribute('data-name') : inputName}" value="${ response['data'][i].value }"/>${ response['data'][i].title }</label>`;
68
+ items += `<label class="tag dropdown__option"><input type="${inputType}" name="${component.hasAttribute('data-name') ? component.getAttribute('data-name') : inputName}" value="${ response['data'][i].value }"/>${ response['data'][i].title }</label>`;
66
69
  }
67
70
 
68
71
  component.insertAdjacentHTML('beforeend', `${items}`);
@@ -101,4 +104,113 @@ export const setTag = (tag):void => {
101
104
  tagIndex = 1;
102
105
 
103
106
  tag?.classList.add(`wider-colour-${tagIndex + 1}`);
104
- }
107
+ }
108
+
109
+ export const addKeyboardEvents = (dropdown, search):void => {
110
+
111
+
112
+
113
+ search.addEventListener('keydown', (e) => {
114
+
115
+ switch ( e.keyCode ) {
116
+ case 40: // down
117
+ e.stopPropagation();
118
+ e.preventDefault();
119
+
120
+ dropdown.querySelector('label:not([slot="checked"]) input')?.focus();
121
+
122
+ break;
123
+ }
124
+ });
125
+
126
+ dropdown.addEventListener('keydown', (event) => {
127
+
128
+ const topLevelmenuItems = dropdown.querySelectorAll(':scope > a, :scope > button, :scope > details > summary, :scope > label:not([slot="checked"]) > input');
129
+ const menuItems = dropdown.querySelectorAll('a, button, input, label:not([slot="checked"]) > input');
130
+
131
+ const activeElement = document.activeElement;
132
+
133
+ if (event && event.target instanceof HTMLElement && event.target.closest('a, button, summary, label:not([slot="checked"]) > input')) {
134
+ const activeItem = document.activeElement;
135
+ const prevIndex = Array.from(topLevelmenuItems).indexOf(activeItem) - 1;
136
+ const nextIndex = Array.from(topLevelmenuItems).indexOf(activeItem) + 1;
137
+
138
+ switch (
139
+ event.keyCode // change to event.key to key to use the above variable
140
+ ) {
141
+ case 27: // Esc
142
+ if (activeItem.closest('details')) {
143
+ event.stopPropagation();
144
+ event.preventDefault();
145
+ activeItem.closest('details').removeAttribute('open');
146
+ activeItem.closest('details').querySelector(':scope summary').focus();
147
+ } else {
148
+ event.stopPropagation();
149
+ //menuButton.focus();
150
+ }
151
+
152
+ break;
153
+ case 32: // Space
154
+ case 13: // Enter
155
+
156
+ break;
157
+ case 35: // end
158
+ event.stopPropagation();
159
+ event.preventDefault();
160
+
161
+ dropdown.querySelector('details[open]')?.removeAttribute('open');
162
+
163
+ Array.from(menuItems)[menuItems.length - 1].focus();
164
+
165
+ break;
166
+ case 36: // home
167
+ event.stopPropagation();
168
+ event.preventDefault();
169
+
170
+ dropdown.querySelector('details[open]')?.removeAttribute('open');
171
+
172
+ Array.from(menuItems)[0].focus();
173
+
174
+ break;
175
+ case 38: // up
176
+ event.stopPropagation();
177
+ event.preventDefault();
178
+
179
+ if (Array.from(topLevelmenuItems).indexOf(activeItem) > -1) {
180
+ if (Array.from(topLevelmenuItems)[prevIndex] != undefined)
181
+ Array.from(topLevelmenuItems)[prevIndex].focus();
182
+ else Array.from(topLevelmenuItems)[topLevelmenuItems.length - 1].focus();
183
+ } else if (activeItem.closest('details')) {
184
+ const subMenuItems = activeItem
185
+ .closest('details')
186
+ .querySelectorAll('a, button, :scope details > summary');
187
+ subPrevIndex = Array.from(subMenuItems).indexOf(activeItem) - 1;
188
+
189
+ if (Array.from(subMenuItems)[subPrevIndex] != undefined) Array.from(subMenuItems)[subPrevIndex].focus();
190
+ else Array.from(subMenuItems)[subMenuItems.length - 1].focus();
191
+ }
192
+
193
+ break;
194
+ case 40: // down
195
+ event.stopPropagation();
196
+ event.preventDefault();
197
+
198
+ if (Array.from(topLevelmenuItems).indexOf(activeItem) > -1) {
199
+ if (Array.from(topLevelmenuItems)[nextIndex] != undefined)
200
+ Array.from(topLevelmenuItems)[nextIndex].focus();
201
+ else Array.from(topLevelmenuItems)[0].focus();
202
+ } else if (activeItem.closest('details')) {
203
+ const subMenuItems = activeItem.closest('details')?.querySelectorAll('a, button, :scope details > summary');
204
+ subNextIndex = Array.from(subMenuItems).indexOf(activeItem) + 1;
205
+
206
+ if (Array.from(subMenuItems)[subNextIndex] != undefined) Array.from(subMenuItems)[subNextIndex].focus();
207
+ else Array.from(subMenuItems)[0].focus();
208
+ }
209
+
210
+ break;
211
+ }
212
+ }
213
+ });
214
+
215
+
216
+ }