@iamproperty/components 5.1.0-beta → 5.1.0-beta10

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 (114) hide show
  1. package/assets/css/components/accordion.global.css.map +1 -1
  2. package/assets/css/components/card.css +1 -1
  3. package/assets/css/components/card.css.map +1 -1
  4. package/assets/css/components/carousel.css +1 -1
  5. package/assets/css/components/carousel.css.map +1 -1
  6. package/assets/css/components/component.native.css +1 -1
  7. package/assets/css/components/component.native.css.map +1 -1
  8. package/assets/css/components/component.reset.css +1 -1
  9. package/assets/css/components/component.reset.css.map +1 -1
  10. package/assets/css/components/fileupload.css +1 -1
  11. package/assets/css/components/fileupload.css.map +1 -1
  12. package/assets/css/components/header.css +1 -1
  13. package/assets/css/components/header.css.map +1 -1
  14. package/assets/css/components/marketing.css +1 -0
  15. package/assets/css/components/marketing.css.map +1 -0
  16. package/assets/css/components/nav.css +1 -1
  17. package/assets/css/components/nav.css.map +1 -1
  18. package/assets/css/components/nav.global.css +1 -1
  19. package/assets/css/components/nav.global.css.map +1 -1
  20. package/assets/css/components/pagination.css +1 -1
  21. package/assets/css/components/pagination.css.map +1 -1
  22. package/assets/css/components/slider.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/img/signin-bg.png +0 -0
  28. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  29. package/assets/js/components/actionbar/actionbar.component.min.js +1 -1
  30. package/assets/js/components/address-lookup/address-lookup.component.js +17 -3
  31. package/assets/js/components/address-lookup/address-lookup.component.min.js +4 -4
  32. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
  33. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  34. package/assets/js/components/card/card.component.js +2 -1
  35. package/assets/js/components/card/card.component.min.js +4 -3
  36. package/assets/js/components/card/card.component.min.js.map +1 -1
  37. package/assets/js/components/carousel/carousel.component.js +61 -0
  38. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  39. package/assets/js/components/fileupload/fileupload.component.min.js +2 -2
  40. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  41. package/assets/js/components/header/header.component.js +6 -12
  42. package/assets/js/components/header/header.component.min.js +8 -14
  43. package/assets/js/components/header/header.component.min.js.map +1 -1
  44. package/assets/js/components/marketing/marketing.component.js +37 -0
  45. package/assets/js/components/nav/nav.component.js +4 -36
  46. package/assets/js/components/nav/nav.component.min.js +10 -13
  47. package/assets/js/components/nav/nav.component.min.js.map +1 -1
  48. package/assets/js/components/notification/notification.component.min.js +1 -1
  49. package/assets/js/components/pagination/pagination.component.min.js +2 -2
  50. package/assets/js/components/search/search.component.js +148 -0
  51. package/assets/js/components/search/search.component.min.js +14 -0
  52. package/assets/js/components/search/search.component.min.js.map +1 -0
  53. package/assets/js/components/table/table.component.min.js +5 -5
  54. package/assets/js/components/table/table.component.min.js.map +1 -1
  55. package/assets/js/components/tabs/tabs.component.min.js +1 -1
  56. package/assets/js/dynamic.js +1 -1
  57. package/assets/js/dynamic.min.js +3 -3
  58. package/assets/js/dynamic.min.js.map +1 -1
  59. package/assets/js/modules/carousel.js +15 -23
  60. package/assets/js/modules/dynamicEvents.js +28 -13
  61. package/assets/js/modules/helpers.js +3 -0
  62. package/assets/js/modules/table.js +8 -6
  63. package/assets/js/scripts.bundle.js +20 -25
  64. package/assets/js/scripts.bundle.js.map +1 -1
  65. package/assets/js/scripts.bundle.min.js +2 -2
  66. package/assets/js/scripts.bundle.min.js.map +1 -1
  67. package/assets/sass/_corefiles.scss +1 -0
  68. package/assets/sass/_elements.scss +1 -1
  69. package/assets/sass/_functions/mixins.scss +16 -0
  70. package/assets/sass/_functions/utilities.scss +0 -17
  71. package/assets/sass/_functions/variables.scss +1 -0
  72. package/assets/sass/components/card.scss +23 -3
  73. package/assets/sass/components/carousel.scss +86 -159
  74. package/assets/sass/components/component.native.scss +86 -3
  75. package/assets/sass/components/fileupload.scss +1 -1
  76. package/assets/sass/components/header.scss +53 -55
  77. package/assets/sass/components/marketing.scss +64 -0
  78. package/assets/sass/components/nav.global.scss +2 -1
  79. package/assets/sass/components/nav.scss +7 -1
  80. package/assets/sass/components/pagination.scss +4 -0
  81. package/assets/sass/elements/admin-panel.scss +9 -7
  82. package/assets/sass/elements/badge.scss +29 -0
  83. package/assets/sass/elements/dialog.scss +4 -4
  84. package/assets/sass/elements/forms.scss +4 -4
  85. package/assets/sass/elements/links.scss +2 -1
  86. package/assets/sass/foundations/reboot.scss +12 -13
  87. package/assets/sass/foundations/root.scss +11 -3
  88. package/assets/sass/helpers/max-height.scss +78 -4
  89. package/assets/sass/templates/auth.scss +112 -0
  90. package/assets/ts/components/address-lookup/address-lookup.component.ts +23 -4
  91. package/assets/ts/components/card/card.component.ts +2 -1
  92. package/assets/ts/components/carousel/README.md +39 -0
  93. package/assets/ts/components/carousel/carousel.component.ts +75 -0
  94. package/assets/ts/components/header/header.component.ts +6 -12
  95. package/assets/ts/components/marketing/marketing.component.ts +49 -0
  96. package/assets/ts/components/nav/README.md +2 -13
  97. package/assets/ts/components/nav/nav.component.ts +4 -47
  98. package/assets/ts/components/search/search.component.ts +177 -0
  99. package/assets/ts/dynamic.ts +1 -1
  100. package/assets/ts/modules/carousel.ts +21 -33
  101. package/assets/ts/modules/dynamicEvents.ts +44 -24
  102. package/assets/ts/modules/helpers.ts +7 -1
  103. package/assets/ts/modules/table.ts +11 -14
  104. package/dist/components.es.js +744 -949
  105. package/dist/components.umd.js +107 -101
  106. package/dist/style.css +1 -1
  107. package/package.json +1 -1
  108. package/src/components/Carousel/Carousel.vue +18 -103
  109. package/src/components/Header/Header.vue +1 -3
  110. package/src/components/Marketing/Marketing.vue +39 -0
  111. package/src/components/Marketing/README.md +20 -0
  112. package/src/components/Nav/README.md +1 -12
  113. package/src/components/Search/Search.vue +25 -0
  114. package/src/components/Carousel/Carousel.spec.js +0 -45
@@ -34,7 +34,7 @@ class iamAddressLookup extends HTMLElement {
34
34
  <div>
35
35
  <label class="mb-2">Search <span class="title text-lowercase"></span> <span class="optional">(Optional)</span>
36
36
  <span>
37
- <input type="text" name="postcode" list="address-lookup__addressess" autoComplete="new-password" aria-autocomplete="none" placeholder="Postcode" />
37
+ <input type="text" name="postcode" list="address-lookup__addressess" autocomplete="off" aria-autocomplete="none" placeholder="Postcode" />
38
38
  <span class="suffix fa-regular fa-search"></span>
39
39
  </span>
40
40
  <span class="invalid-feedback">Required Adddress fields missing</span>
@@ -251,9 +251,28 @@ class iamAddressLookup extends HTMLElement {
251
251
  let listString = '';
252
252
  response.forEach((address, index) => {
253
253
 
254
-
255
- let values = JSON.stringify(address.value);
256
- listString += `<option value="${address['label']}, ${postcode}" data-values='${values}'></option>`;
254
+ // Deal with agent platform response
255
+ if(typeof address.value == "object"){
256
+ let values = JSON.stringify(address.value);
257
+ listString += `<option value="${address['label']}, ${postcode}" data-values='${values}'></option>`;
258
+ }
259
+ else {
260
+ let values = JSON.stringify(address);
261
+
262
+ let itemString = '';
263
+
264
+ for (const [key, value] of Object.entries(address)) {
265
+
266
+ if(key == "address_number_name")
267
+ itemString += `${value} `;
268
+ else if(key != "postcode" && key != "address_title")
269
+ itemString += `${value}, `;
270
+ }
271
+
272
+ listString += `<option value="${itemString}${postcode}" data-values='${values}'></option>`;
273
+ }
274
+
275
+
257
276
  });
258
277
  list.innerHTML = listString;
259
278
 
@@ -32,8 +32,9 @@ class iamCard extends HTMLElement {
32
32
  ${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
33
33
  </style>
34
34
  <div class="card ${classList}" tabindex="0" role="button">
35
- ${this.hasAttribute('data-image') ? `<div class="card__head"><img src="${this.getAttribute('data-image')}" alt="" loading="lazy" /></div>` : ''}
35
+ ${this.hasAttribute('data-image') ? `<div class="card__head"><img src="${this.getAttribute('data-image')}" alt="" loading="lazy" /><div class="card__badges"><slot name="badges"></slot></div></div>` : ''}
36
36
  <div class="card__body">
37
+ ${!this.hasAttribute('data-image') ? `<div class="card__badges"><slot name="badges"></slot></div>` : ''}
37
38
  ${this.classList.contains('card--filter') && this.hasAttribute('data-total') ? `<div class="card__total">${this.getAttribute('data-total')}</div>` : ''}
38
39
  ${this.hasAttribute('data-illustration') ? `<div class="card__illustration"><img src="${this.getAttribute('data-illustration')}" alt="" loading="lazy" /></div>` : ''}
39
40
  <slot></slot>
@@ -0,0 +1,39 @@
1
+ **Add the below to your initialise script**
2
+
3
+ ```
4
+ import('../node_modules/@iamproperty/components/assets/js/components/filterlist/filterlist.component.min').then(module => { // Might need to update the path
5
+
6
+ if (!window.customElements.get(`iam-filterlist`))
7
+ window.customElements.define(`iam-filterlist`, module.default);
8
+
9
+ }).catch((err) => {
10
+ console.log(err.message);
11
+ });
12
+ ```
13
+
14
+ **Add the below HTML code to where you want the component to live.**
15
+
16
+ ```
17
+ <iam-header class="bg-secondary" image="/shutterstock_1229155495.webp">
18
+ <ul class="breadcrumb" slot="breadcrumb">
19
+ <li><a href="/">Home</a></li>
20
+ <li><a href="/top">Top level</a></li>
21
+ </ul>
22
+ <h1>Page title</h1>
23
+ <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</p>
24
+ </iam-header>
25
+ ```
26
+
27
+ **Properties**
28
+
29
+ | Option | Type | Default Value | Description |
30
+ | ------ | ---- | ------------- | ----------- |
31
+ | image | String | - | Optional image url to display in the background |
32
+
33
+
34
+ **Slots**
35
+
36
+ | Option | Default Value | Description |
37
+ | ------ | ------------- | ----------- |
38
+ | default | - | Will display underneath the heading inside of the white box |
39
+ | breadcrumb | - | An optional space to add a breadcrumb trail list. |
@@ -0,0 +1,75 @@
1
+ // @ts-nocheck
2
+ import carousel from "../../modules/carousel";
3
+
4
+ // Data layer Web component created
5
+ window.dataLayer = window.dataLayer || [];
6
+ window.dataLayer.push({
7
+ "event": "customElementRegistered",
8
+ "element": "carousel"
9
+ });
10
+
11
+ class iamCarousel extends HTMLElement {
12
+
13
+ constructor(){
14
+ super();
15
+ this.attachShadow({ mode: 'open'});
16
+
17
+ const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets';
18
+ const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
19
+ const loadCSS = `@import "${assetLocation}/css/components/carousel.css";`;
20
+
21
+ const template = document.createElement('template');
22
+ template.innerHTML = `
23
+ <style>
24
+ @import "${coreCSS}";
25
+ ${loadCSS}
26
+ ${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
27
+ </style>
28
+ <div class="carousel" :id="'carousel'+id">
29
+ <div class="carousel__wrapper">
30
+ <div class="carousel__inner">
31
+
32
+ <slot></slot>
33
+ </div>
34
+
35
+ <div class="carousel__controls">
36
+
37
+ </div>
38
+
39
+ <button class="btn btn-prev" data-go="0" disabled>Prev</button>
40
+ <button class="btn btn-next" data-go="2">Next</button>
41
+
42
+ </div>
43
+ </div>
44
+ `;
45
+ this.shadowRoot.appendChild(template.content.cloneNode(true));
46
+ }
47
+
48
+ connectedCallback() {
49
+
50
+ const carouselElement = this.shadowRoot.querySelector('.carousel');
51
+ const row = this.querySelector('.row');
52
+ const carouselControls = this.shadowRoot.querySelector('.carousel__controls');
53
+
54
+ let itemCount = this.querySelectorAll(':scope > .row > .col').length
55
+
56
+ carouselElement.setAttribute('data-row-class',row.className);
57
+
58
+ if(this.classList.contains('hide-btns'))
59
+ carouselElement.classList.add('hide-btns');
60
+
61
+ if(this.classList.contains('hide-controls'))
62
+ carouselElement.classList.add('hide-controls');
63
+
64
+ // populate the pips
65
+ let pips = "";
66
+ for (let i = 1; i <= itemCount; i++) {
67
+ pips += `<button class="control-${i}" data-slide="${i}" ${i == 1 ? "aria-current":""}>Slide ${i}</button>`;
68
+ }
69
+ carouselControls.innerHTML = pips;
70
+
71
+ carousel(carouselElement,row);
72
+ }
73
+ }
74
+
75
+ export default iamCarousel;
@@ -25,18 +25,12 @@ class iamHeader extends HTMLElement {
25
25
  ${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
26
26
  </style>
27
27
  <div class="header-banner">
28
- <div class="container" part="container">
29
- <slot name="breadcrumb"></slot>
30
- <div class="header-banner__inner">
31
- <slot></slot>
32
- </div>
33
- </div>
34
28
  <picture>
35
- <!-- Actual image only loaded on desktops -->
36
- <source srcset="" media="(min-width: 62em)">
37
- <!-- Placeholder image -->
38
29
  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" alt="" lazy="" />
39
30
  </picture>
31
+ <div class="container">
32
+ <slot></slot>
33
+ </div>
40
34
  </div>
41
35
  `;
42
36
  this.shadowRoot.appendChild(template.content.cloneNode(true));
@@ -44,13 +38,13 @@ class iamHeader extends HTMLElement {
44
38
 
45
39
  connectedCallback() {
46
40
 
47
- this.classList.add('loaded');
41
+ this.classList.add('bg-primary');
48
42
 
49
43
  const picture = this.shadowRoot.querySelector('picture');
50
- const source = this.shadowRoot.querySelector('picture source');
44
+ const source = this.shadowRoot.querySelector('picture img');
51
45
 
52
46
  if(this.hasAttribute('image'))
53
- source.setAttribute('srcset', this.getAttribute('image'));
47
+ source.setAttribute('src', this.getAttribute('image'));
54
48
  else
55
49
  picture.remove();
56
50
 
@@ -0,0 +1,49 @@
1
+ // @ts-nocheck
2
+
3
+ // Data layer Web component created
4
+ window.dataLayer = window.dataLayer || [];
5
+ window.dataLayer.push({
6
+ "event": "customElementRegistered",
7
+ "element": "Marketing"
8
+ });
9
+
10
+ class iamMarketing extends HTMLElement {
11
+
12
+ constructor(){
13
+ super();
14
+ this.attachShadow({ mode: 'open'});
15
+
16
+ const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets'
17
+ const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
18
+ const loadCSS = `@import "${assetLocation}/css/components/marketing.css";`;
19
+
20
+ const template = document.createElement('template');
21
+ template.innerHTML = `
22
+ <style>
23
+ @import "${coreCSS}";
24
+ ${loadCSS}
25
+
26
+ </style>
27
+ <link rel="stylesheet" href="https://kit.fontawesome.com/26fdbf0179.css" crossorigin="anonymous" />
28
+ <div class="marketing">
29
+
30
+ <slot></slot>
31
+ </div>
32
+ `;
33
+ this.shadowRoot.appendChild(template.content.cloneNode(true));
34
+ }
35
+
36
+ connectedCallback() {
37
+
38
+ this.classList.add('invert-colours');
39
+
40
+ if(this.hasAttribute('data-img')){
41
+ this.shadowRoot.querySelector('.marketing').insertAdjacentHTML(
42
+ 'afterbegin',
43
+ `<figure><img src="${this.getAttribute('data-img')}" alt="" /></figure>`,
44
+ );
45
+ }
46
+ }
47
+ }
48
+
49
+ export default iamMarketing;
@@ -37,9 +37,6 @@ import('../node_modules/@iamproperty/components/assets/js/components/nav/nav.com
37
37
 
38
38
  | Option | Type | Default Value | Description |
39
39
  | ------ | ---- | ------------- | ----------- |
40
- | data-search | String | - | Optional, displays a search button and form. The value passed through is used for the forms action attribute. |
41
- | data-list | String | - | Optional string with an ID of a datalist, note this list needs to be added as an element in the component |
42
- | data-prevent-search | String | - | Flag that prevents the search form submitting allowing it to used purely with JavaScript |
43
40
  | data-searcd-open | String | - | Flag that opens the search bar on desktop on page load. |
44
41
 
45
42
  **Slots**
@@ -51,18 +48,10 @@ import('../node_modules/@iamproperty/components/assets/js/components/nav/nav.com
51
48
  | secondary | - | Moves the link upto the top of the navbar on desktop |
52
49
  | actions | - | A place to add buttons |
53
50
  | dual | - | Plave the link or list to the right of the nav, forcing the default slot to the left. |
51
+ | search | - | A place to include a form with search functionality |
54
52
 
55
53
  **Class modifiers**
56
54
 
57
55
  - Adding a class of **.bg-primary** will change the background of the navbar without chaning the menu background.
58
56
  - Adding a class of **.nav--sticky** will add etxra styling to make the navbar stick to the top of the page
59
- - Adding a class of **.nav--xs-sticky** will add etxra styling to make the navbar stick to the top of the page BUT only on the mobile view.
60
-
61
- **Dispatched events**
62
-
63
- | Event | Dispatched when | Details passed|
64
- | ------ | ------------- | ----------- |
65
- | search-keydown | When a user uses the search input field and triggers the keydown event. | { search: $inputValue } |
66
- | search-keyup | When a user uses the search input field and triggers the keyup event. | { search: $inputValue } |
67
- | search-change | When a user uses the search input field and triggers the change event. | { search: $inputValue } |
68
- | search-submit | When a user uses the search form and triggers the submit event. | { search: $inputValue } |
57
+ - Adding a class of **.nav--xs-sticky** will add etxra styling to make the navbar stick to the top of the page BUT only on the mobile view.
@@ -48,7 +48,6 @@ class iamNav extends HTMLElement {
48
48
  <slot name="menus"></slot>
49
49
  </div>
50
50
  </div>
51
- <div class="lists"></div>
52
51
  <div class="backdrop" part="backdrop"></div>
53
52
  `;
54
53
 
@@ -285,7 +284,7 @@ class iamNav extends HTMLElement {
285
284
  });
286
285
 
287
286
  // Search
288
- if(this.hasAttribute('data-search')){
287
+ if(this.querySelector('[slot="search"]')){
289
288
  menu.classList.add('has-search');
290
289
  let searchWrapper = this.shadowRoot.querySelector('#search-wrapper');
291
290
 
@@ -293,24 +292,20 @@ class iamNav extends HTMLElement {
293
292
  searchWrapper.insertAdjacentHTML('afterbegin',`<button class="btn btn-secondary btn-compact fa-search me-0 mb-0" id="search-button" aria-controls="search-dialog">Open Search field</button>
294
293
  <dialog id="search-dialog">
295
294
  <div class="container">
296
- <form action="${this.hasAttribute('data-search') ? this.getAttribute('data-search') : ''}" class="row" id="search-form">
295
+ <div class="row">
297
296
  <div class="col mb-0 ms-auto col-md-7">
298
- <label for="search" class="visually-hidden">Search</label>
299
- <button class="suffix me-0 mb-0"><i class="fa-regular fa-search"></i></button>
300
- <input type="search" class="" id="search" name="search" required="" autocomplete="off" data-list="${this.hasAttribute('data-list') ? this.getAttribute('data-list') : ''}" />
297
+ <slot name="search"></slot>
301
298
  </div>
302
299
  <div class="col d-none d-md-block mw-fit-content ms-3">
303
300
  <button class="btn btn-compact btn-secondary fa-xmark-large m-0 mb-0" type="button" id="search-close">Close search field</button>
304
301
  </div>
305
- </form>
302
+ </div>
306
303
  </div>
307
304
  </dialog>`);
308
305
 
309
306
  let searchButton = this.shadowRoot.querySelector('#search-button');
310
307
  let searchClose = this.shadowRoot.querySelector('#search-close');
311
308
  let searchDialog = this.shadowRoot.querySelector('#search-dialog');
312
- let searchInput = this.shadowRoot.querySelector('#search');
313
- let searchForm = this.shadowRoot.querySelector('#search-form');
314
309
 
315
310
  if(this.hasAttribute('data-search-open')){
316
311
 
@@ -336,44 +331,6 @@ class iamNav extends HTMLElement {
336
331
  searchButton.removeAttribute('aria-expanded');
337
332
  });
338
333
 
339
- // Search events
340
- searchInput.addEventListener('keydown', (event) => {
341
-
342
- const keyupEvent = new CustomEvent("search-keydown", { detail: { search: searchInput.value } });
343
- this.dispatchEvent(keyupEvent);
344
- });
345
-
346
- searchInput.addEventListener('keyup', (event) => {
347
-
348
- if (searchInput.value.length >= 3 && searchInput.hasAttribute('data-list'))
349
- searchInput.setAttribute("list", searchInput.getAttribute('data-list'));
350
- else
351
- searchInput.removeAttribute("list");
352
-
353
- const keyupEvent = new CustomEvent("search-keyup", { detail: { search: searchInput.value } });
354
- this.dispatchEvent(keyupEvent);
355
- });
356
-
357
- searchInput.addEventListener('change', (event) => {
358
-
359
- const changeEvent = new CustomEvent("search-change", { detail: { search: searchInput.value } });
360
- this.dispatchEvent(changeEvent);
361
- });
362
-
363
- searchForm.addEventListener('submit', (event) => {
364
-
365
- if(this.hasAttribute('data-prevent-search'))
366
- event.preventDefault();
367
-
368
- const submitEvent = new CustomEvent("search-submit", { detail: { search: searchInput.value } });
369
- this.dispatchEvent(submitEvent);
370
- });
371
-
372
- // Make sure any child lists are available to the search input
373
- this.querySelectorAll('datalist').forEach((list) => {
374
-
375
- iamNav.shadowRoot.querySelector('.lists').insertAdjacentElement('beforeend',list);
376
- });
377
334
  }
378
335
  }
379
336
  }
@@ -0,0 +1,177 @@
1
+ // @ts-nocheck
2
+ import Cookies from 'js-cookie';
3
+ import { safeID, resolvePath, isTraversable } from '../../modules/helpers'
4
+
5
+ // Data layer Web component created
6
+ window.dataLayer = window.dataLayer || [];
7
+ window.dataLayer.push({
8
+ "event": "customElementRegistered",
9
+ "element": "Search"
10
+ });
11
+
12
+ class iamSearch extends HTMLElement {
13
+
14
+ constructor(){
15
+ super();
16
+ this.attachShadow({ mode: 'open'});
17
+
18
+ const assetLocation = document.body.hasAttribute('data-assets-location') ? document.body.getAttribute('data-assets-location') : '/assets'
19
+ const coreCSS = document.body.hasAttribute('data-core-css') ? document.body.getAttribute('data-core-css') : `${assetLocation}/css/core.min.css`;
20
+
21
+ const template = document.createElement('template');
22
+ template.innerHTML = `
23
+ <style>
24
+ @import "${coreCSS}";
25
+
26
+ </style>
27
+ <link rel="stylesheet" href="https://kit.fontawesome.com/26fdbf0179.css" crossorigin="anonymous" />
28
+ <slot></slot>
29
+ `;
30
+ this.shadowRoot.appendChild(template.content.cloneNode(true));
31
+ }
32
+
33
+ async connectedCallback() {
34
+
35
+ const searchWrapper = this;
36
+ const inputField = this.querySelector('input');
37
+ const valueSchema = this.hasAttribute('data-value-schema') ? this.getAttribute('data-value-schema') : 'value';
38
+ const displaySchema = this.hasAttribute('data-display-schema') ? this.getAttribute('data-display-schema') : 'label';
39
+ const loopSchema = this.hasAttribute('data-schema') ? this.getAttribute('data-schema') : '';
40
+ let datalist = this.querySelector('datalist');
41
+ let searched = [];
42
+
43
+ // Clone original input field, re-name and use for display purposes
44
+ const displayInputField = inputField.cloneNode();
45
+ displayInputField.setAttribute('name',`${inputField.getAttribute('name')}Alt`);
46
+ inputField.removeAttribute('data-change-events');
47
+ displayInputField.removeAttribute('id');
48
+
49
+ inputField.after(displayInputField);
50
+
51
+ // Hide original input field
52
+ inputField.setAttribute('type','hidden');
53
+
54
+ // if data list does not exist then create one and append
55
+ if(!datalist){
56
+
57
+ datalist = document.createElement("datalist");
58
+ let listID = safeID('list');
59
+ datalist.setAttribute('id',listID);
60
+ searchWrapper.appendChild(datalist);
61
+
62
+ displayInputField.setAttribute('list',listID);
63
+ }
64
+
65
+ // on change update oringinal field with the actual value and use displayed input for the nice display text
66
+ displayInputField.addEventListener('change', (event) => {
67
+
68
+ let match = datalist.querySelector(`option[value="${displayInputField.value}"]`);
69
+
70
+ if(match){
71
+ inputField.value = match.getAttribute('data-value');
72
+ }
73
+ });
74
+
75
+ // Search the endpoint when 3 characters has been added
76
+ if(searchWrapper.hasAttribute('data-url')){
77
+
78
+ displayInputField.addEventListener('keyup', (event) => {
79
+
80
+ if(displayInputField.value.length == 3 && !searched.includes(displayInputField.value)){
81
+ search(displayInputField.value);
82
+ searched.push(displayInputField.value);
83
+ }
84
+ });
85
+
86
+ displayInputField.addEventListener('change', (event) => {
87
+
88
+ if(displayInputField.value.length >= 3 && !searched.includes(displayInputField.value.substring(0,3))){
89
+ search(displayInputField.value.substring(0,3));
90
+ searched.push(displayInputField.value.substring(0,3));
91
+ }
92
+ });
93
+ }
94
+
95
+ const search = async (searchterm) => {
96
+
97
+ let ajaxURL = searchWrapper.getAttribute('data-url');
98
+ ajaxURL += `${encodeURI(searchterm)}`;
99
+
100
+ // Setup controller vars if not already set
101
+ if(!window.controller)
102
+ window.controller = [];
103
+
104
+ // Abort if controller already present for this url
105
+ if(window.controller[ajaxURL])
106
+ window.controller[ajaxURL].abort();
107
+
108
+ // Create a new controller so it can be aborted if new fetch made
109
+ window.controller[ajaxURL] = new AbortController();
110
+ const { signal } = controller[ajaxURL];
111
+
112
+ try {
113
+ await fetch(ajaxURL, {
114
+ signal: signal,
115
+ method: 'get',
116
+ credentials: 'same-origin',
117
+ headers: new Headers({
118
+ 'Content-Type': 'application/json',
119
+ Accept: 'application/json',
120
+ 'X-Requested-With': 'XMLHttpRequest',
121
+ 'X-XSRF-TOKEN': Cookies.get('XSRF-TOKEN')
122
+ })
123
+ })
124
+ .then((response) => response.json()).then((response) => {
125
+
126
+ // populate datalist
127
+ let listString = '';
128
+ let loopValues = resolvePath(response, loopSchema, '');
129
+
130
+ if(isTraversable(loopValues) && typeof loopValues.forEach == 'function') {
131
+ loopValues.forEach((item, index) => {
132
+ let actualValue = resolvePath(item, valueSchema, '');
133
+ let displayValue = resolvePath(item, displaySchema, '').replace('\n',', ');
134
+
135
+ if(!datalist.querySelector(`option[data-value="${actualValue}"]`))
136
+ listString += `<option value="${displayValue}" data-value='${actualValue}'></option>`;
137
+ });
138
+ }
139
+ else if (typeof loopValues == 'object'){
140
+
141
+ for (const [key, value] of Object.entries(loopValues)) {
142
+
143
+ if(isTraversable(value) && typeof value.forEach == 'function') {
144
+ value.forEach((item, index) => {
145
+ let actualValue = resolvePath(item, valueSchema, '');
146
+ let displayValue = resolvePath(item, displaySchema, '').replace('\n',', ');
147
+
148
+ if(!datalist.querySelector(`option[data-value="${actualValue}"]`))
149
+ listString += `<option value="${key}: ${displayValue}" data-value='${actualValue}'></option>`;
150
+ });
151
+ }
152
+ }
153
+ }
154
+
155
+ datalist.innerHTML += listString;
156
+
157
+ return response;
158
+ });
159
+
160
+ } catch (error) {
161
+ console.log(error);
162
+ }
163
+ }
164
+
165
+ if(searchWrapper.hasAttribute('data-prevent-submit')){
166
+
167
+ const form = searchWrapper.closest('form');
168
+
169
+ form.addEventListener('submit', (e) => {
170
+
171
+ e.preventDefault();
172
+ });
173
+ }
174
+ }
175
+ }
176
+
177
+ export default iamSearch;
@@ -14,7 +14,7 @@ import youtubeVideo from '../js/modules/youtubevideo'
14
14
 
15
15
  import iamNotification from './components/notification/notification.component'
16
16
 
17
- const components = ['accordion','header','tabs', 'table','card','pagination','filterlist', 'applied-filters'];
17
+ const components = ['accordion','header','tabs', 'table','card','pagination','filterlist', 'applied-filters', 'nav', 'marketing'];
18
18
  const prefix = "iam"
19
19
  const options = {
20
20
  rootMargin: '50px',