@iamproperty/components 7.8.2--beta2 → 7.8.2--beta4

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 (206) 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/advanced-select.component.css +1 -1
  6. package/assets/css/components/advanced-select.component.css.map +1 -1
  7. package/assets/css/components/applied-filters.css +1 -1
  8. package/assets/css/components/applied-filters.css.map +1 -1
  9. package/assets/css/components/banner.preload.css +1 -0
  10. package/assets/css/components/banner.preload.css.map +1 -0
  11. package/assets/css/components/calendar.component.css +1 -1
  12. package/assets/css/components/calendar.component.css.map +1 -1
  13. package/assets/css/components/card.component.css +1 -1
  14. package/assets/css/components/card.component.css.map +1 -1
  15. package/assets/css/components/card.module.css +1 -1
  16. package/assets/css/components/card.module.css.map +1 -1
  17. package/assets/css/components/card.preload.css +1 -0
  18. package/assets/css/components/card.preload.css.map +1 -0
  19. package/assets/css/components/carousel.component.css +1 -1
  20. package/assets/css/components/carousel.component.css.map +1 -1
  21. package/assets/css/components/carousel.config.css +1 -1
  22. package/assets/css/components/carousel.config.css.map +1 -1
  23. package/assets/css/components/config.component.css +1 -1
  24. package/assets/css/components/config.component.css.map +1 -1
  25. package/assets/css/components/content.component.css +1 -1
  26. package/assets/css/components/content.component.css.map +1 -1
  27. package/assets/css/components/fileupload.css +1 -1
  28. package/assets/css/components/fileupload.css.map +1 -1
  29. package/assets/css/components/filter-card.component.css +1 -1
  30. package/assets/css/components/filter-card.component.css.map +1 -1
  31. package/assets/css/components/multiselect.css +1 -1
  32. package/assets/css/components/multiselect.css.map +1 -1
  33. package/assets/css/components/nav.component.css +1 -1
  34. package/assets/css/components/nav.component.css.map +1 -1
  35. package/assets/css/components/pagination.css +1 -1
  36. package/assets/css/components/pagination.css.map +1 -1
  37. package/assets/css/components/record-card.component.css +1 -1
  38. package/assets/css/components/record-card.component.css.map +1 -1
  39. package/assets/css/components/search.component.css +1 -1
  40. package/assets/css/components/search.component.css.map +1 -1
  41. package/assets/css/components/skeleton.global.css +1 -1
  42. package/assets/css/components/skeleton.global.css.map +1 -1
  43. package/assets/css/components/slider.css +1 -1
  44. package/assets/css/components/slider.css.map +1 -1
  45. package/assets/css/components/split-button.component.css +1 -1
  46. package/assets/css/components/split-button.component.css.map +1 -1
  47. package/assets/css/components/std-nav-standalone.component.css +1 -1
  48. package/assets/css/components/std-nav-standalone.component.css.map +1 -1
  49. package/assets/css/components/tabs.component.css +1 -1
  50. package/assets/css/components/tabs.component.css.map +1 -1
  51. package/assets/css/components/tag.component.css +1 -1
  52. package/assets/css/components/tag.component.css.map +1 -1
  53. package/assets/css/components/video-card.component.css +1 -1
  54. package/assets/css/components/video-card.component.css.map +1 -1
  55. package/assets/css/core.min.css +1 -1
  56. package/assets/css/core.min.css.map +1 -1
  57. package/assets/css/elements/badge-tag.css +1 -1
  58. package/assets/css/elements/badge-tag.css.map +1 -1
  59. package/assets/css/elements/dropdown.css +1 -1
  60. package/assets/css/elements/dropdown.css.map +1 -1
  61. package/assets/css/elements/forms.css +1 -1
  62. package/assets/css/elements/forms.css.map +1 -1
  63. package/assets/css/elements/links--global.css +1 -1
  64. package/assets/css/elements/links--global.css.map +1 -1
  65. package/assets/css/elements/links.css +1 -1
  66. package/assets/css/elements/links.css.map +1 -1
  67. package/assets/css/style.min.css +1 -1
  68. package/assets/css/style.min.css.map +1 -1
  69. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  70. package/assets/js/components/actionbar/actionbar.component.min.js +2 -2
  71. package/assets/js/components/address-lookup/address-lookup.component.min.js +4 -4
  72. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
  73. package/assets/js/components/advanced-select/advanced-select.component.min.js +2 -2
  74. package/assets/js/components/applied-filters/applied-filters.component.min.js +2 -2
  75. package/assets/js/components/banner/banner.component.min.js +1 -1
  76. package/assets/js/components/barchart/barchart.component.min.js +1 -1
  77. package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
  78. package/assets/js/components/bone/bone.component.min.js +1 -1
  79. package/assets/js/components/button/button.component.min.js +1 -1
  80. package/assets/js/components/calendar/calendar.component.min.js +2 -2
  81. package/assets/js/components/card/card.component.js +114 -125
  82. package/assets/js/components/card/card.component.min.js +7 -7
  83. package/assets/js/components/card/card.component.min.js.map +1 -1
  84. package/assets/js/components/carousel/carousel.component.js +83 -29
  85. package/assets/js/components/carousel/carousel.component.min.js +16 -11
  86. package/assets/js/components/carousel/carousel.component.min.js.map +1 -1
  87. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  88. package/assets/js/components/config/config.component.min.js +7 -7
  89. package/assets/js/components/config/config.component.min.js.map +1 -1
  90. package/assets/js/components/content/content.component.js +28 -69
  91. package/assets/js/components/content/content.component.min.js +4 -4
  92. package/assets/js/components/content/content.component.min.js.map +1 -1
  93. package/assets/js/components/darkmode/darkmode.component.min.js +1 -1
  94. package/assets/js/components/doughnutchart/doughnutchart.component.min.js +1 -1
  95. package/assets/js/components/fileupload/fileupload.component.min.js +2 -2
  96. package/assets/js/components/filter-card/filter-card.component.min.js +5 -5
  97. package/assets/js/components/filter-card/filter-card.component.min.js.map +1 -1
  98. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  99. package/assets/js/components/form/form.component.min.js +1 -1
  100. package/assets/js/components/header/header.component.min.js +1 -1
  101. package/assets/js/components/inline-edit/inline-edit.component.min.js +1 -1
  102. package/assets/js/components/input/input.component.min.js +1 -1
  103. package/assets/js/components/input-range/input-range.component.min.js +1 -1
  104. package/assets/js/components/marketing/marketing.component.min.js +1 -1
  105. package/assets/js/components/menu/menu.component.min.js +1 -1
  106. package/assets/js/components/milestone/milestone.component.min.js +1 -1
  107. package/assets/js/components/milestone-group/milestone-group.component.min.js +1 -1
  108. package/assets/js/components/modal/modal.component.min.js +1 -1
  109. package/assets/js/components/multi-step/multi-step.component.min.js +1 -1
  110. package/assets/js/components/multi-step-modal/multi-step-modal.component.min.js +1 -1
  111. package/assets/js/components/multiselect/multiselect.component.min.js +4 -4
  112. package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -1
  113. package/assets/js/components/nav/nav.component.min.js +2 -2
  114. package/assets/js/components/notification/notification.component.min.js +1 -1
  115. package/assets/js/components/pagination/pagination.component.min.js +5 -5
  116. package/assets/js/components/password/password.component.min.js +1 -1
  117. package/assets/js/components/popover/popover.component.min.js +1 -1
  118. package/assets/js/components/rank/rank.component.min.js +1 -1
  119. package/assets/js/components/rankings/rankings.component.min.js +1 -1
  120. package/assets/js/components/rating/rating.component.min.js +1 -1
  121. package/assets/js/components/record-card/record-card.component.min.js +6 -6
  122. package/assets/js/components/record-card/record-card.component.min.js.map +1 -1
  123. package/assets/js/components/search/search.component.js +234 -186
  124. package/assets/js/components/search/search.component.min.js +12 -7
  125. package/assets/js/components/search/search.component.min.js.map +1 -1
  126. package/assets/js/components/skeleton/skeleton.component.min.js +1 -1
  127. package/assets/js/components/slider/slider.component.min.js +2 -2
  128. package/assets/js/components/split-button/split-button.component.min.js +2 -2
  129. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js +5 -5
  130. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js.map +1 -1
  131. package/assets/js/components/std-nav/std-nav.component.js +10 -9
  132. package/assets/js/components/std-nav/std-nav.component.min.js +9 -12
  133. package/assets/js/components/std-nav/std-nav.component.min.js.map +1 -1
  134. package/assets/js/components/std-nav-standalone/std-nav-standalone.component.min.js +5 -5
  135. package/assets/js/components/std-nav-standalone/std-nav-standalone.component.min.js.map +1 -1
  136. package/assets/js/components/table/table.component.min.js +1 -1
  137. package/assets/js/components/table-ajax/table-ajax.component.min.js +1 -1
  138. package/assets/js/components/table-basic/table-basic.component.min.js +1 -1
  139. package/assets/js/components/table-no-submit/table-no-submit.component.min.js +1 -1
  140. package/assets/js/components/table-submit/table-submit.component.min.js +1 -1
  141. package/assets/js/components/tabs/tabs.component.min.js +4 -4
  142. package/assets/js/components/tag/tag.component.min.js +3 -3
  143. package/assets/js/components/tag/tag.component.min.js.map +1 -1
  144. package/assets/js/components/tooltip/tooltip.component.min.js +1 -1
  145. package/assets/js/components/video/video.component.min.js +1 -1
  146. package/assets/js/components/video-card/video-card.component.min.js +9 -9
  147. package/assets/js/components/video-card/video-card.component.min.js.map +1 -1
  148. package/assets/js/components/video-modal/video-modal.component.min.js +1 -1
  149. package/assets/js/components/word-count/word-count.component.min.js +1 -1
  150. package/assets/js/modules/card.module.js +12 -11
  151. package/assets/js/modules/content.js +40 -8
  152. package/assets/js/modules/content.test.js +62 -12
  153. package/assets/js/modules/data-layer.js +7 -6
  154. package/assets/js/modules/dropdown.js +0 -1
  155. package/assets/js/modules/nav.js +10 -3
  156. package/assets/js/modules/search.js +153 -0
  157. package/assets/js/modules/search.test.js +125 -0
  158. package/assets/js/modules/tabs.test.js +64 -12
  159. package/assets/js/modules/testimonial.test.js +44 -6
  160. package/assets/js/modules/videos.test.js +61 -13
  161. package/assets/js/scripts.bundle.js +3 -3
  162. package/assets/js/scripts.bundle.js.map +1 -1
  163. package/assets/js/scripts.bundle.min.js +2 -2
  164. package/assets/js/scripts.bundle.min.js.map +1 -1
  165. package/assets/sass/_components.scss +2 -63
  166. package/assets/sass/components/banner.preload.scss +26 -0
  167. package/assets/sass/components/card.component.scss +1 -7
  168. package/assets/sass/components/card.module.scss +6 -6
  169. package/assets/sass/components/card.preload.scss +80 -0
  170. package/assets/sass/components/carousel.component.scss +165 -0
  171. package/assets/sass/components/carousel.config.scss +85 -249
  172. package/assets/sass/components/content.component.scss +0 -7
  173. package/assets/sass/components/nav.component.scss +2 -1
  174. package/assets/sass/components/search.component.scss +89 -7
  175. package/assets/sass/components/skeleton.global.scss +4 -0
  176. package/assets/sass/elements/badge-tag.css +1 -1
  177. package/assets/sass/elements/dropdown.css +2 -0
  178. package/assets/sass/elements/forms.scss +0 -27
  179. package/assets/sass/elements/links--global.scss +40 -2
  180. package/assets/sass/foundations/root.scss +0 -1
  181. package/assets/sass/utilities/border.css +1 -1
  182. package/assets/sass/utilities/js-display.css +2 -3
  183. package/assets/ts/components/card/card.component.ts +72 -62
  184. package/assets/ts/components/carousel/carousel.component.ts +84 -19
  185. package/assets/ts/components/content/content.component.ts +36 -100
  186. package/assets/ts/components/search/search.component.ts +257 -185
  187. package/assets/ts/components/std-nav/std-nav.component.ts +17 -16
  188. package/assets/ts/html.d.ts +6 -0
  189. package/assets/ts/modules/card.module.ts +20 -12
  190. package/assets/ts/modules/content.test.ts +84 -12
  191. package/assets/ts/modules/content.ts +56 -9
  192. package/assets/ts/modules/data-layer.ts +7 -11
  193. package/assets/ts/modules/dropdown.ts +0 -2
  194. package/assets/ts/modules/nav.ts +12 -3
  195. package/assets/ts/modules/search.test.ts +142 -0
  196. package/assets/ts/modules/search.ts +206 -0
  197. package/assets/ts/modules/tabs.test.ts +79 -12
  198. package/assets/ts/modules/testimonial.test.ts +45 -6
  199. package/assets/ts/modules/videos.test.ts +74 -14
  200. package/dist/components.es.js +25 -25
  201. package/dist/components.umd.js +164 -157
  202. package/package.json +1 -1
  203. package/assets/js/modules/carousel.js +0 -214
  204. package/assets/js/modules/carousel.test.js +0 -18
  205. package/assets/ts/modules/carousel.test.ts +0 -27
  206. package/assets/ts/modules/carousel.ts +0 -301
@@ -1,10 +1,18 @@
1
- import Cookies from '../../../../node_modules/js-cookie/dist/js.cookie.mjs';
2
- import { safeID, resolvePath, isTraversable } from '../../modules/helpers';
3
- import advancedSelect from '../../modules/advanced-select';
1
+ import search, { filterDatalist, datalistSelectOption } from '../../modules/search';
2
+
3
+ const getIntegerAttribute = (element: HTMLElement, attributeName: string, fallback: number): number => {
4
+ const value = Number.parseInt(element.getAttribute(attributeName) || '', 10);
5
+
6
+ return Number.isNaN(value) ? fallback : value;
7
+ };
8
+
9
+ const getOptionFromEvent = (event: Event): HTMLOptionElement | null =>
10
+ event.target instanceof HTMLElement ? event.target.closest<HTMLOptionElement>('option') : null;
4
11
 
5
12
  // Data layer Web component created
6
- window.dataLayer = window.dataLayer || [];
7
- window.dataLayer.push({
13
+ const searchWindow = window as WindowWithDataLayer;
14
+ searchWindow.dataLayer = searchWindow.dataLayer || [];
15
+ searchWindow.dataLayer.push({
8
16
  event: 'customElementRegistered',
9
17
  element: 'Search',
10
18
  });
@@ -12,246 +20,310 @@ window.dataLayer.push({
12
20
  class iamSearch extends HTMLElement {
13
21
  constructor() {
14
22
  super();
15
- this.attachShadow({ mode: 'open' });
23
+ const shadowRoot = this.attachShadow({ mode: 'open' });
16
24
 
17
- const assetLocation = document.body.hasAttribute('data-assets-location')
18
- ? document.body.getAttribute('data-assets-location')
19
- : '/assets';
25
+ const assetLocation = document.body.getAttribute('data-assets-location') || '/assets';
20
26
 
21
27
  const loadCSS = `@import "${assetLocation}/css/components/search.component.css";`;
22
28
 
23
29
  const template = document.createElement('template');
24
- template.innerHTML = `
30
+ template.innerHTML = /* HTML */ `
25
31
  <style>
26
32
  ${loadCSS}
27
33
  </style>
28
34
  <link rel="stylesheet" href="https://kit.fontawesome.com/8bd0fca975.css" crossorigin="anonymous" />
29
- <span class="wrapper"><span class="input__wrapper"><slot></slot></span><span class="suffix fa-regular fa-search"></span></span>
35
+ <span class="wrapper">
36
+ <span class="input__wrapper">
37
+ <slot></slot>
38
+ <button class="clear-search btn btn-action" type="button"><i class="fa-light fa-times me-0"></i></button>
39
+ </span>
40
+ <button class="suffix ${this.getAttribute('data-icon') || 'fa-regular fa-search'}"></button>
41
+ </span>
30
42
  <slot name="datalist"></slot>
31
43
  `;
32
- this.shadowRoot.appendChild(template.content.cloneNode(true));
44
+ shadowRoot.appendChild(template.content.cloneNode(true));
33
45
  }
34
46
 
35
- async connectedCallback(): void {
36
-
37
- // Make the datalist a dropdown
38
- this.classList.add('dropdown__wrapper');
47
+ connectedCallback(): void {
48
+ const shadowRoot = this.shadowRoot;
39
49
 
40
- if(this.querySelector('input.input--sm'))
41
- this.classList.add('hasInputSm');
50
+ if (!shadowRoot) return;
42
51
 
43
-
44
- if(this.querySelector('label'))
45
- this.classList.add('has-label');
52
+ let datalistElement = this.querySelector<HTMLDataListElement>('datalist');
53
+ const inputElement = this.querySelector<HTMLInputElement>('input');
54
+ const suffixElement = shadowRoot.querySelector<HTMLButtonElement>('.suffix');
55
+ const clearBtn = shadowRoot.querySelector<HTMLButtonElement>('.clear-search');
46
56
 
47
- // eslint-disable-next-line @typescript-eslint/no-this-alias
48
- const searchWrapper = this;
49
- const inputField = this.querySelector('input');
50
- const valueSchema = this.hasAttribute('data-value-schema') ? this.getAttribute('data-value-schema') : 'value';
51
- const displaySchema = this.hasAttribute('data-display-schema') ? this.getAttribute('data-display-schema') : 'label';
52
- const loopSchema = this.hasAttribute('data-schema') ? this.getAttribute('data-schema') : '';
53
- let datalist = this.querySelector('datalist');
54
- let minLength = this.hasAttribute('data-min-length') ? this.getAttribute('data-min-length') : 0;
57
+ let minLength = this.hasAttribute('data-min-length') ? getIntegerAttribute(this, 'data-min-length', 1) : 1;
55
58
 
56
- if (searchWrapper.hasAttribute('data-url') && !this.hasAttribute('data-min-length')) {
59
+ if (this.hasAttribute('data-url') && !this.hasAttribute('data-min-length')) {
57
60
 
58
61
  minLength = 3;
59
62
  }
60
63
 
61
- // Clone original input field, re-name and use for display purposes
62
- const displayInputField = inputField.cloneNode();
63
- displayInputField.setAttribute('name', `${inputField.getAttribute('name')}Alt`);
64
- inputField.removeAttribute('data-change-events');
65
- displayInputField.removeAttribute('id');
64
+ if(!inputElement || !suffixElement) return;
65
+
66
+ // #region maintain the original placeholder value in a data attribute to allow for it to be reset when the field is emptied
67
+ const originalPlaceholder = inputElement.getAttribute('placeholder');
68
+
69
+ if(originalPlaceholder !== null)
70
+ this.setAttribute('data-original-placeholder', originalPlaceholder);
71
+ // #endregion
72
+
73
+
74
+ // #region transform datalist into dropdown
66
75
 
67
- inputField.after(displayInputField);
76
+ // Turn off the browser's default datalist functionality to allow for a custom implementation
77
+ inputElement.setAttribute('autocomplete', 'off');
78
+ inputElement.setAttribute('aria-autocomplete', 'none');
68
79
 
69
- // Hide original input field
70
- inputField.setAttribute('type', 'hidden');
80
+ if(inputElement && inputElement.hasAttribute('list')){
71
81
 
72
- // if data list does not exist then create one and append
73
- if (!datalist) {
74
- datalist = document.createElement('datalist');
75
- const listID = safeID('list');
76
- datalist.setAttribute('id', listID);
77
- searchWrapper.appendChild(datalist);
82
+ inputElement.setAttribute('data-list', inputElement.getAttribute('list') || '');
83
+ inputElement.setAttribute('list', '');
84
+ }
78
85
 
79
- displayInputField.setAttribute('list', listID);
86
+ if (!datalistElement) {
87
+ datalistElement = document.createElement('datalist');
88
+ const listID = `${inputElement?.getAttribute('name')}-list`;
89
+ datalistElement.setAttribute('id', listID);
90
+ inputElement?.setAttribute('data-list', listID);
91
+ this.appendChild(datalistElement);
80
92
  }
93
+ datalistElement.setAttribute('slot', 'datalist');
94
+
95
+ datalistElement.querySelectorAll<HTMLOptionElement>('option').forEach((option) => {
96
+
97
+ option.setAttribute('tabindex', '0');
98
+
99
+ if(option.textContent == '' && option.hasAttribute('value')){
100
+ option.textContent = option.getAttribute('value');
101
+ }
81
102
 
82
- displayInputField.addEventListener('change', function (e) {
83
- inputField.value = displayInputField.value;
84
103
  });
85
104
 
86
- advancedSelect(this, displayInputField, datalist, false);
105
+ datalistElement.addEventListener('click', (event) => {
106
+ const optionElement = getOptionFromEvent(event);
107
+
108
+ if (optionElement) {
109
+
110
+ event.stopPropagation();
111
+ event.preventDefault();
112
+
113
+ if (document.activeElement instanceof HTMLElement) document.activeElement.blur();
114
+ this.classList.remove('js-show-datalist');
115
+ datalistSelectOption(this, inputElement, optionElement);
116
+ }
117
+ });
118
+ // #endregion
87
119
 
120
+ // #region control input field
121
+ inputElement.addEventListener('input', () => {
88
122
 
89
- const checkMatch = (): void => {
90
- const match = datalist.querySelector(`option[value="${displayInputField.value}" i]`);
91
- const subMatch = datalist.querySelector(`option[value*="${displayInputField.value}" i]`);
123
+ if(inputElement.value.length >= 1){
124
+ this.classList.add('has-value');
125
+ }
126
+ else{
127
+ this.classList.remove('has-value');
128
+ }
92
129
 
93
- if (match) {
94
- inputField.value = match.getAttribute('data-actual-value');
95
- displayInputField.value = match.getAttribute('data-actual-value');
130
+ if(inputElement.value.length >= minLength){
131
+ //inputElement.removeAttribute('data-value');
132
+ this.classList.add('js-show-datalist');
96
133
 
97
- displayInputField.classList.remove('is-invalid');
98
- displayInputField.closest('label').removeAttribute('data-error');
99
- }
100
- else if (displayInputField.value.length >= minLength && !subMatch) {
101
- displayInputField.classList.add('is-invalid');
102
- displayInputField.closest('label').setAttribute('data-error', 'No results returned');
103
134
 
104
- if(searchWrapper.hasAttribute('data-url'))
105
- datalist.innerHTML = '';
106
- }
135
+ if(this.hasAttribute('data-url')){
136
+ void search(this, datalistElement, inputElement.value)
137
+ }
138
+ else {
139
+ filterDatalist(datalistElement, inputElement.value);
140
+ }
141
+ }
107
142
  else {
108
- displayInputField.classList.remove('is-invalid');
109
- displayInputField.closest('label').removeAttribute('data-error');
143
+ this.classList.remove('js-show-datalist');
110
144
  }
111
- }
112
145
 
113
-
114
- const search = async (searchterm): any => {
115
-
116
- if(!this.getAttribute('data-url'))
117
- return false;
118
-
119
- let ajaxURL = this.getAttribute('data-url');
120
- ajaxURL += `${encodeURI(searchterm)}`;
121
-
122
- // Setup controller vars if not already set
123
- if (!window.controller) window.controller = [];
124
-
125
- // Abort if controller already present for this url
126
- if (window.controller[ajaxURL]) window.controller[ajaxURL].abort();
127
-
128
- // Create a new controller so it can be aborted if new fetch made
129
- window.controller[ajaxURL] = new AbortController();
130
- const { signal } = controller[ajaxURL];
131
-
132
- try {
133
- await fetch(ajaxURL, {
134
- signal: signal,
135
- method: 'get',
136
- credentials: 'same-origin',
137
- mode: 'no-cors',
138
- headers: new Headers({
139
- 'Content-Type': 'application/json',
140
- Accept: 'application/json',
141
- 'X-Requested-With': 'XMLHttpRequest',
142
- 'X-XSRF-TOKEN': Cookies.get('XSRF-TOKEN'),
143
- }),
144
- })
145
- .then((response) => response.json())
146
- .then((response) => {
147
- // populate datalist
148
- let listString = '';
149
- const loopValues = resolvePath(response, loopSchema, '');
150
-
151
- if (isTraversable(loopValues) && typeof loopValues.forEach == 'function') {
152
- loopValues.forEach((item) => {
153
- const actualValue = resolvePath(item, valueSchema, '');
154
- const displayValue = resolvePath(item, displaySchema, '').replace('\n', ', ');
155
-
156
- if (!datalist.querySelector(`option[data-actual-value="${actualValue}"]`))
157
- listString += `<option value="${displayValue}" data-actual-value="${actualValue}">${displayValue}</option>`;
158
- });
159
- } else if (typeof loopValues == 'object') {
160
- for (const [key, value] of Object.entries(loopValues)) {
161
- if (isTraversable(value) && typeof value.forEach == 'function') {
162
- value.forEach((item) => {
163
- const actualValue = resolvePath(item, valueSchema, '');
164
- const displayValue = resolvePath(item, displaySchema, '').replace('\n', ', ');
165
-
166
- if (!datalist.querySelector(`option[data-actual-value="${actualValue}"]`))
167
- listString += `<option value="${key}: ${displayValue}" data-actual-value='${actualValue}'>${key}: ${displayValue}</option>`;
168
- });
169
- }
170
- }
171
- }
146
+ });
147
+ inputElement.addEventListener('focus', () => {
172
148
 
173
- datalist.innerHTML += listString;
174
-
175
- // filter the list on the client side just in case
176
- const text = searchterm.toUpperCase();
177
- for (const option of datalist.options) {
178
- if (option.value.toUpperCase().indexOf(text) > -1) {
179
- option.style.display = 'block';
180
- option.classList.remove('hide');
181
- } else {
182
- option.style.display = 'none';
183
- option.classList.add('hide');
184
- }
185
- }
149
+ if(inputElement.value == inputElement.getAttribute('data-value')){
150
+ const selectedValue = inputElement.getAttribute('data-value') || '';
151
+
152
+ inputElement.value = '';
153
+ inputElement.setAttribute('placeholder', selectedValue);
154
+ this.classList.remove('js-show-datalist');
155
+ }
156
+ else if(inputElement.value.length >= minLength){
157
+ this.classList.add('js-show-datalist');
158
+ }
159
+ });
160
+
161
+ inputElement.addEventListener('blur', () => {
162
+ const selectedValue = inputElement.getAttribute('data-value');
186
163
 
187
- searchWrapper.classList.add('was-validated');
188
- checkMatch();
164
+ if(!inputElement.value && selectedValue){
189
165
 
190
- return response;
191
- });
192
- } catch (error) {
193
- console.log(error);
166
+ inputElement.value = selectedValue;
167
+ //inputElement.setAttribute('placeholder', inputElement.getAttribute('data-value'));
168
+ //this.classList.remove('js-show-datalist');
194
169
  }
195
- };
170
+ // Set timeout to allow click event to fire on options before hiding the list again
196
171
 
172
+ setTimeout(() => {
173
+ this.classList.remove('js-force-show-datalist');
174
+ this.classList.remove('js-show-datalist');
175
+ }, 200);
197
176
 
198
- datalist.addEventListener('click', function (event) {
177
+ const placeholder = inputElement.getAttribute('data-placeholder');
199
178
 
200
- if (event && event.target instanceof HTMLElement && event.target.closest('option')) {
201
-
202
- const option = event.target.closest('option');
203
- const value = option?.hasAttribute('data-actual-value') ? option?.getAttribute('data-actual-value') : option?.getAttribute('data-value');
204
- inputField.value = value;
179
+ if(placeholder)
180
+ inputElement.setAttribute('placeholder', placeholder);
181
+ });
182
+
183
+ // #endregion
184
+
185
+ // #region control suffix button
186
+ suffixElement.addEventListener('click', () => {
187
+ const form = this.closest<HTMLFormElement>('form');
188
+
189
+ if(form && !this.hasAttribute('data-prevent-submit')){
205
190
 
206
- const changeEvent = new CustomEvent('value-change', {
207
- detail: { value: value },
208
- });
209
- searchWrapper.dispatchEvent(changeEvent);
191
+ form.requestSubmit();
192
+ }
193
+ else {
194
+ inputElement.focus();
195
+ this.classList.add('js-force-show-datalist');
210
196
  }
211
197
  });
198
+ // #endregion
199
+
200
+ // #region keyboard navigation
201
+
202
+ this.addEventListener('keydown', (event) => {
212
203
 
213
- this.addEventListener('close-button-pressed', function (event) {
214
204
 
215
- if(searchWrapper.hasAttribute('data-url')) {
216
- datalist.innerHTML = '';
205
+ switch (event.key) {
206
+
207
+ case 'ArrowDown':
208
+ //event.stopPropagation();
209
+ //event.preventDefault();
210
+
211
+ if(event && event.target instanceof HTMLElement && event.target == inputElement){
212
+ this.querySelector<HTMLOptionElement>('datalist option:not(.js-hide)')?.focus();
213
+ }
214
+
215
+ break;
216
+
217
217
  }
218
- inputField?.value = '';
219
218
 
220
- searchWrapper.classList.remove('was-validated');
221
-
222
- displayInputField.classList.remove('is-invalid');
223
- displayInputField.closest('label').removeAttribute('data-error');
219
+ /*
220
+ if (event && event.target instanceof HTMLElement && event.target.closest('a, button, summary')) {
221
+ const activeItem = document.activeElement;
222
+ const prevIndex = Array.from(topLevelmenuItems).indexOf(activeItem) - 1;
223
+ const nextIndex = Array.from(topLevelmenuItems).indexOf(activeItem) + 1;
224
+
225
+ switch (
226
+ event.keyCode // change to event.key to key to use the above variable
227
+ ) {
228
+ case 27: // Esc
229
+ if (activeItem.closest('details')) {
230
+ event.stopPropagation();
231
+ event.preventDefault();
232
+ activeItem.closest('details').removeAttribute('open');
233
+ activeItem.closest('details').querySelector(':scope summary').focus();
234
+ } else {
235
+ event.stopPropagation();
236
+ menuButton.focus();
237
+ }
238
+
239
+ break;
240
+ case 32: // Space
241
+ case 13: // Enter
242
+ break;
243
+ case 35: // end
244
+ event.stopPropagation();
245
+ event.preventDefault();
246
+
247
+ this.querySelector('details[open]').removeAttribute('open');
248
+ Array.from(menuItems)[menuItems.length - 1].focus();
249
+
250
+ break;
251
+ case 36: // home
252
+ event.stopPropagation();
253
+ event.preventDefault();
254
+
255
+ this.querySelector('details[open]').removeAttribute('open');
256
+ Array.from(menuItems)[0].focus();
257
+
258
+ break;
259
+ case 38: // up
260
+ event.stopPropagation();
261
+ event.preventDefault();
262
+
263
+ if (Array.from(topLevelmenuItems).indexOf(activeItem) > -1) {
264
+ if (Array.from(topLevelmenuItems)[prevIndex] != undefined)
265
+ Array.from(topLevelmenuItems)[prevIndex].focus();
266
+ else Array.from(topLevelmenuItems)[topLevelmenuItems.length - 1].focus();
267
+ } else if (activeItem.closest('details')) {
268
+ const subMenuItems = activeItem
269
+ .closest('details')
270
+ .querySelectorAll('a, button, :scope details > summary');
271
+ subPrevIndex = Array.from(subMenuItems).indexOf(activeItem) - 1;
272
+
273
+ if (Array.from(subMenuItems)[subPrevIndex] != undefined) Array.from(subMenuItems)[subPrevIndex].focus();
274
+ else Array.from(subMenuItems)[subMenuItems.length - 1].focus();
275
+ }
276
+
277
+ break;
278
+ case 40: // down
279
+ event.stopPropagation();
280
+ event.preventDefault();
281
+
282
+ if (Array.from(topLevelmenuItems).indexOf(activeItem) > -1) {
283
+ if (Array.from(topLevelmenuItems)[nextIndex] != undefined)
284
+ Array.from(topLevelmenuItems)[nextIndex].focus();
285
+ else Array.from(topLevelmenuItems)[0].focus();
286
+ } else if (activeItem.closest('details')) {
287
+ const subMenuItems = activeItem
288
+ .closest('details')
289
+ .querySelectorAll('a, button, :scope details > summary');
290
+ subNextIndex = Array.from(subMenuItems).indexOf(activeItem) + 1;
291
+
292
+ if (Array.from(subMenuItems)[subNextIndex] != undefined) Array.from(subMenuItems)[subNextIndex].focus();
293
+ else Array.from(subMenuItems)[0].focus();
294
+ }
295
+
296
+ break;
297
+ }
298
+ }
299
+
300
+ */
224
301
  });
225
302
 
303
+ // #endregion
226
304
 
227
- // Search the endpoint when 3 characters has been added
228
- if (searchWrapper.hasAttribute('data-url')) {
305
+ // #region empty button
306
+ clearBtn?.addEventListener('click', () => {
229
307
 
230
- displayInputField.addEventListener('input', () => {
308
+ this.classList.remove('js-show-datalist');
309
+ inputElement.value = '';
310
+ inputElement.removeAttribute('data-value');
311
+ inputElement.focus();
312
+ this.classList.remove('has-value');
231
313
 
232
- if(displayInputField.value.length < minLength){
233
- datalist.innerHTML = '';
234
- }
314
+ inputElement.setAttribute('placeholder', this.getAttribute('data-original-placeholder') || '');
235
315
 
236
- if (displayInputField.value.length == minLength) {
237
- search(displayInputField.value);
238
- }
239
- });
240
- }
241
- else {
242
- // on change update oringinal field with the actual value and use displayed input for the nice display text
243
- displayInputField.addEventListener('input', () => {
244
- checkMatch();
245
- });
246
- }
316
+ const inputName = inputElement.getAttribute('name');
317
+ const alternateInput = inputName ? this.querySelector<HTMLInputElement>(`[name="${inputName}Alt"]`) : null;
318
+
319
+ alternateInput?.remove();
247
320
 
248
- if (searchWrapper.hasAttribute('data-prevent-submit')) {
249
- const form = searchWrapper.closest('form');
321
+ datalistElement.querySelectorAll<HTMLOptionElement>('option').forEach((option) => {
250
322
 
251
- form.addEventListener('submit', (e) => {
252
- e.preventDefault();
323
+ option.classList.remove('active');
253
324
  });
254
- }
325
+ });
326
+
255
327
  }
256
328
  }
257
329
 
@@ -17,26 +17,25 @@ class iamSTDNav extends HTMLElement {
17
17
  defaultToNav = ():void => {
18
18
 
19
19
  const defaultContent = this.innerHTML;
20
- this.innerHTML = `<iam-nav>
20
+ this.innerHTML = `<iam-nav ${(this.hasAttribute('class') ? `class="${this.getAttribute('class')}"`:'')}>
21
21
  ${defaultContent}
22
22
  </iam-nav>`;
23
23
  }
24
24
 
25
25
  transformToNav = (data):void => {
26
-
26
+
27
+ const navElement = this.querySelector('iam-nav') ?? this;
28
+
27
29
  // Remove current links
28
- this.querySelector('iam-nav').querySelectorAll(`:scope > *`).forEach((element) => {
30
+ navElement.querySelectorAll(`:scope > *`).forEach((element) => {
29
31
 
30
32
  if(!element.hasAttribute('slot'))
31
33
  element.remove();
32
34
  });
33
35
 
34
- const defaultContent = this.querySelector('iam-nav').innerHTML;
36
+ const defaultContent = navElement.innerHTML;
35
37
 
36
- this.innerHTML = `<iam-nav ${(this.hasAttribute('class') ? `class="${this.getAttribute('class')}"`:'')}>
37
- ${defaultContent}
38
- ${populateNav(data)}
39
- </iam-nav>`;
38
+ navElement.innerHTML = `${defaultContent}${populateNav(data)}`;
40
39
  }
41
40
 
42
41
  defaultToSecondary = (): void => {
@@ -65,17 +64,18 @@ class iamSTDNav extends HTMLElement {
65
64
  this.outerHTML = `${defaultContent}`;
66
65
  }
67
66
 
68
-
69
67
  async connectedCallback(): void {
70
-
68
+
71
69
  const component = this;
72
70
  this.wrapper = this.shadowRoot?.querySelector('.wrapper');
73
71
 
74
72
  if (!window.customElements.get(`iam-nav`))
75
73
  window.customElements.define(`iam-nav`, iamNav);
76
-
74
+
77
75
  if(this.hasAttribute('data-hub')){
78
76
  this.defaultToNav();
77
+
78
+ this.querySelector('.nav--menu.js-show')?.classList.remove('js-show');
79
79
  }
80
80
  else {
81
81
  //this.defaultToSecondary(); TODO: change this to show default content but still be able to update
@@ -86,15 +86,17 @@ class iamSTDNav extends HTMLElement {
86
86
  const data = await loadNavData(Cookies).then(
87
87
  (data) => {
88
88
 
89
-
90
89
  if(typeof data == 'string'){
91
-
90
+
92
91
  return data;
93
92
  }
94
93
 
95
94
  //console.log(data);
96
95
  if(this.hasAttribute('data-hub')){
97
- this.transformToNav(data);
96
+
97
+ const filteredData = data.filter(section => section.attributes.title != "Learning and support");
98
+
99
+ this.transformToNav(filteredData);
98
100
  }
99
101
  else {
100
102
  this.transformToSecondary(data);
@@ -104,13 +106,12 @@ class iamSTDNav extends HTMLElement {
104
106
  }
105
107
  );
106
108
 
107
-
109
+
108
110
  const userData = await loadUserData(Cookies).then(
109
111
  (data) => {
110
112
 
111
113
  setEnabledLinks(component,data);
112
114
 
113
-
114
115
  Array.from(document.querySelectorAll('[data-variable]')).forEach((element) => {
115
116
 
116
117
  if(data.attributes[element.getAttribute('data-variable')])
@@ -2,3 +2,9 @@ declare module '*.html' {
2
2
  const value: string;
3
3
  export default value;
4
4
  }
5
+
6
+ type DataLayerEvent = Record<string, unknown>;
7
+
8
+ type WindowWithDataLayer = Window & {
9
+ dataLayer: DataLayerEvent[];
10
+ };