@iamproperty/components 7.8.2--beta3 → 7.8.2--beta5

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 (235) 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/banner.preload.css +1 -0
  8. package/assets/css/components/banner.preload.css.map +1 -0
  9. package/assets/css/components/calendar.component.css +1 -1
  10. package/assets/css/components/calendar.component.css.map +1 -1
  11. package/assets/css/components/card.component.css +1 -1
  12. package/assets/css/components/card.component.css.map +1 -1
  13. package/assets/css/components/card.module.css +1 -1
  14. package/assets/css/components/card.module.css.map +1 -1
  15. package/assets/css/components/card.preload.css +1 -0
  16. package/assets/css/components/card.preload.css.map +1 -0
  17. package/assets/css/components/carousel.component.css +1 -1
  18. package/assets/css/components/carousel.component.css.map +1 -1
  19. package/assets/css/components/carousel.config.css +1 -1
  20. package/assets/css/components/carousel.config.css.map +1 -1
  21. package/assets/css/components/config.component.css +1 -1
  22. package/assets/css/components/config.component.css.map +1 -1
  23. package/assets/css/components/content.component.css +1 -1
  24. package/assets/css/components/content.component.css.map +1 -1
  25. package/assets/css/components/fileupload.css +1 -1
  26. package/assets/css/components/fileupload.css.map +1 -1
  27. package/assets/css/components/filter-card.component.css +1 -1
  28. package/assets/css/components/filter-card.component.css.map +1 -1
  29. package/assets/css/components/modal.component.css +1 -1
  30. package/assets/css/components/modal.component.css.map +1 -1
  31. package/assets/css/components/multi-step-modal.component.css +1 -1
  32. package/assets/css/components/multi-step-modal.component.css.map +1 -1
  33. package/assets/css/components/multiselect.css +1 -1
  34. package/assets/css/components/multiselect.css.map +1 -1
  35. package/assets/css/components/nav.component.css +1 -1
  36. package/assets/css/components/nav.component.css.map +1 -1
  37. package/assets/css/components/nav.global.css +1 -1
  38. package/assets/css/components/nav.global.css.map +1 -1
  39. package/assets/css/components/notification.global.css +1 -1
  40. package/assets/css/components/notification.global.css.map +1 -1
  41. package/assets/css/components/pagination.css +1 -1
  42. package/assets/css/components/pagination.css.map +1 -1
  43. package/assets/css/components/record-card.component.css +1 -1
  44. package/assets/css/components/record-card.component.css.map +1 -1
  45. package/assets/css/components/search.component.css +1 -1
  46. package/assets/css/components/search.component.css.map +1 -1
  47. package/assets/css/components/skeleton.global.css +1 -1
  48. package/assets/css/components/skeleton.global.css.map +1 -1
  49. package/assets/css/components/slider.css +1 -1
  50. package/assets/css/components/slider.css.map +1 -1
  51. package/assets/css/components/split-button.component.css +1 -1
  52. package/assets/css/components/split-button.component.css.map +1 -1
  53. package/assets/css/components/std-nav-standalone.component.css +1 -1
  54. package/assets/css/components/std-nav-standalone.component.css.map +1 -1
  55. package/assets/css/components/tabs.component.css +1 -1
  56. package/assets/css/components/tabs.component.css.map +1 -1
  57. package/assets/css/components/tag.component.css +1 -1
  58. package/assets/css/components/tag.component.css.map +1 -1
  59. package/assets/css/components/video-card.component.css +1 -1
  60. package/assets/css/components/video-card.component.css.map +1 -1
  61. package/assets/css/components/video-modal.component.css +1 -1
  62. package/assets/css/components/video-modal.component.css.map +1 -1
  63. package/assets/css/core.min.css +1 -1
  64. package/assets/css/core.min.css.map +1 -1
  65. package/assets/css/elements/dialog.css +1 -1
  66. package/assets/css/elements/dialog.css.map +1 -1
  67. package/assets/css/elements/dropdown.css +1 -1
  68. package/assets/css/elements/dropdown.css.map +1 -1
  69. package/assets/css/elements/forms.css +1 -1
  70. package/assets/css/elements/forms.css.map +1 -1
  71. package/assets/css/elements/links--global.css +1 -1
  72. package/assets/css/elements/links--global.css.map +1 -1
  73. package/assets/css/elements/links.css +1 -1
  74. package/assets/css/elements/links.css.map +1 -1
  75. package/assets/css/style.min.css +1 -1
  76. package/assets/css/style.min.css.map +1 -1
  77. package/assets/js/components/accordion/accordion.component.min.js +1 -1
  78. package/assets/js/components/actionbar/actionbar.component.min.js +3 -3
  79. package/assets/js/components/address-lookup/address-lookup.component.min.js +4 -4
  80. package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
  81. package/assets/js/components/advanced-select/advanced-select.component.min.js +2 -2
  82. package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
  83. package/assets/js/components/banner/banner.component.min.js +1 -1
  84. package/assets/js/components/barchart/barchart.component.min.js +1 -1
  85. package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
  86. package/assets/js/components/bone/bone.component.min.js +1 -1
  87. package/assets/js/components/button/button.component.min.js +1 -1
  88. package/assets/js/components/calendar/calendar.component.min.js +2 -2
  89. package/assets/js/components/card/card.component.js +114 -125
  90. package/assets/js/components/card/card.component.min.js +7 -7
  91. package/assets/js/components/card/card.component.min.js.map +1 -1
  92. package/assets/js/components/carousel/carousel.component.js +83 -29
  93. package/assets/js/components/carousel/carousel.component.min.js +16 -11
  94. package/assets/js/components/carousel/carousel.component.min.js.map +1 -1
  95. package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
  96. package/assets/js/components/config/config.component.min.js +7 -7
  97. package/assets/js/components/config/config.component.min.js.map +1 -1
  98. package/assets/js/components/content/content.component.js +28 -69
  99. package/assets/js/components/content/content.component.min.js +4 -4
  100. package/assets/js/components/content/content.component.min.js.map +1 -1
  101. package/assets/js/components/darkmode/darkmode.component.min.js +1 -1
  102. package/assets/js/components/doughnutchart/doughnutchart.component.min.js +1 -1
  103. package/assets/js/components/fileupload/fileupload.component.min.js +2 -2
  104. package/assets/js/components/filter-card/filter-card.component.min.js +5 -5
  105. package/assets/js/components/filter-card/filter-card.component.min.js.map +1 -1
  106. package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
  107. package/assets/js/components/form/form.component.js +42 -151
  108. package/assets/js/components/form/form.component.min.js +3 -3
  109. package/assets/js/components/form/form.component.min.js.map +1 -1
  110. package/assets/js/components/header/header.component.min.js +1 -1
  111. package/assets/js/components/inline-edit/inline-edit.component.min.js +1 -1
  112. package/assets/js/components/input/input.component.min.js +1 -1
  113. package/assets/js/components/input-range/input-range.component.min.js +1 -1
  114. package/assets/js/components/marketing/marketing.component.min.js +1 -1
  115. package/assets/js/components/menu/menu.component.min.js +1 -1
  116. package/assets/js/components/milestone/milestone.component.min.js +1 -1
  117. package/assets/js/components/milestone-group/milestone-group.component.min.js +1 -1
  118. package/assets/js/components/modal/modal.component.js +16 -11
  119. package/assets/js/components/modal/modal.component.min.js +7 -7
  120. package/assets/js/components/modal/modal.component.min.js.map +1 -1
  121. package/assets/js/components/multi-step/multi-step.component.min.js +1 -1
  122. package/assets/js/components/multi-step-modal/multi-step-modal.component.min.js +4 -4
  123. package/assets/js/components/multiselect/multiselect.component.min.js +4 -4
  124. package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -1
  125. package/assets/js/components/nav/nav.component.js +88 -79
  126. package/assets/js/components/nav/nav.component.min.js +8 -8
  127. package/assets/js/components/nav/nav.component.min.js.map +1 -1
  128. package/assets/js/components/notification/notification.component.min.js +2 -2
  129. package/assets/js/components/pagination/pagination.component.min.js +5 -5
  130. package/assets/js/components/password/password.component.min.js +1 -1
  131. package/assets/js/components/popover/popover.component.min.js +1 -1
  132. package/assets/js/components/rank/rank.component.min.js +1 -1
  133. package/assets/js/components/rankings/rankings.component.min.js +1 -1
  134. package/assets/js/components/rating/rating.component.min.js +1 -1
  135. package/assets/js/components/record-card/record-card.component.min.js +6 -6
  136. package/assets/js/components/record-card/record-card.component.min.js.map +1 -1
  137. package/assets/js/components/search/search.component.js +235 -186
  138. package/assets/js/components/search/search.component.min.js +12 -7
  139. package/assets/js/components/search/search.component.min.js.map +1 -1
  140. package/assets/js/components/skeleton/skeleton.component.min.js +1 -1
  141. package/assets/js/components/slider/slider.component.min.js +2 -2
  142. package/assets/js/components/split-button/split-button.component.min.js +2 -2
  143. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js +5 -5
  144. package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js.map +1 -1
  145. package/assets/js/components/std-nav/std-nav.component.js +12 -9
  146. package/assets/js/components/std-nav/std-nav.component.min.js +12 -15
  147. package/assets/js/components/std-nav/std-nav.component.min.js.map +1 -1
  148. package/assets/js/components/std-nav-standalone/std-nav-standalone.component.min.js +5 -5
  149. package/assets/js/components/std-nav-standalone/std-nav-standalone.component.min.js.map +1 -1
  150. package/assets/js/components/table/table.component.min.js +1 -1
  151. package/assets/js/components/table-ajax/table-ajax.component.min.js +1 -1
  152. package/assets/js/components/table-basic/table-basic.component.min.js +1 -1
  153. package/assets/js/components/table-no-submit/table-no-submit.component.min.js +1 -1
  154. package/assets/js/components/table-submit/table-submit.component.min.js +1 -1
  155. package/assets/js/components/tabs/tabs.component.min.js +4 -4
  156. package/assets/js/components/tag/tag.component.min.js +3 -3
  157. package/assets/js/components/tag/tag.component.min.js.map +1 -1
  158. package/assets/js/components/tooltip/tooltip.component.min.js +1 -1
  159. package/assets/js/components/video/video.component.min.js +1 -1
  160. package/assets/js/components/video-card/video-card.component.min.js +9 -9
  161. package/assets/js/components/video-card/video-card.component.min.js.map +1 -1
  162. package/assets/js/components/video-modal/video-modal.component.min.js +5 -5
  163. package/assets/js/components/word-count/word-count.component.min.js +1 -1
  164. package/assets/js/modules/card.module.js +12 -11
  165. package/assets/js/modules/content.js +40 -8
  166. package/assets/js/modules/content.test.js +62 -12
  167. package/assets/js/modules/data-layer.js +7 -6
  168. package/assets/js/modules/dropdown.js +0 -1
  169. package/assets/js/modules/form.js +129 -0
  170. package/assets/js/modules/form.test.js +132 -0
  171. package/assets/js/modules/nav.js +10 -3
  172. package/assets/js/modules/search.js +153 -0
  173. package/assets/js/modules/search.test.js +125 -0
  174. package/assets/js/modules/tabs.test.js +64 -12
  175. package/assets/js/modules/test-dom.js +5 -0
  176. package/assets/js/modules/testimonial.test.js +44 -6
  177. package/assets/js/modules/videos.test.js +61 -13
  178. package/assets/js/scripts.bundle.js +3 -3
  179. package/assets/js/scripts.bundle.js.map +1 -1
  180. package/assets/js/scripts.bundle.min.js +2 -2
  181. package/assets/js/scripts.bundle.min.js.map +1 -1
  182. package/assets/sass/_components.scss +2 -63
  183. package/assets/sass/_utilities.scss +1 -0
  184. package/assets/sass/components/banner.preload.scss +26 -0
  185. package/assets/sass/components/card.component.scss +1 -7
  186. package/assets/sass/components/card.module.scss +6 -6
  187. package/assets/sass/components/card.preload.scss +80 -0
  188. package/assets/sass/components/carousel.component.scss +165 -0
  189. package/assets/sass/components/carousel.config.scss +90 -249
  190. package/assets/sass/components/content.component.scss +0 -7
  191. package/assets/sass/components/modal.component.scss +5 -1
  192. package/assets/sass/components/nav.component.scss +2 -1
  193. package/assets/sass/components/nav.global.scss +0 -10
  194. package/assets/sass/components/notification.global.scss +8 -0
  195. package/assets/sass/components/search.component.scss +89 -7
  196. package/assets/sass/components/skeleton.global.scss +4 -0
  197. package/assets/sass/elements/dialog.scss +43 -0
  198. package/assets/sass/elements/dropdown.css +2 -0
  199. package/assets/sass/elements/forms.scss +0 -27
  200. package/assets/sass/elements/links--global.scss +40 -2
  201. package/assets/sass/foundations/colours.scss +0 -24
  202. package/assets/sass/foundations/reboot.scss +4 -0
  203. package/assets/sass/foundations/root.scss +0 -1
  204. package/assets/sass/utilities/js-display.css +2 -3
  205. package/assets/sass/utilities/wordpress.css +7 -0
  206. package/assets/ts/components/card/card.component.ts +72 -62
  207. package/assets/ts/components/carousel/carousel.component.ts +84 -19
  208. package/assets/ts/components/content/content.component.ts +36 -100
  209. package/assets/ts/components/form/form.component.ts +54 -213
  210. package/assets/ts/components/modal/modal.component.ts +27 -19
  211. package/assets/ts/components/nav/nav.component.ts +107 -95
  212. package/assets/ts/components/search/search.component.ts +260 -184
  213. package/assets/ts/components/std-nav/std-nav.component.ts +20 -17
  214. package/assets/ts/html.d.ts +6 -0
  215. package/assets/ts/modules/card.module.ts +19 -11
  216. package/assets/ts/modules/content.test.ts +84 -12
  217. package/assets/ts/modules/content.ts +56 -9
  218. package/assets/ts/modules/data-layer.ts +7 -11
  219. package/assets/ts/modules/dropdown.ts +0 -2
  220. package/assets/ts/modules/form.test.ts +183 -0
  221. package/assets/ts/modules/form.ts +210 -0
  222. package/assets/ts/modules/nav.ts +12 -3
  223. package/assets/ts/modules/search.test.ts +142 -0
  224. package/assets/ts/modules/search.ts +206 -0
  225. package/assets/ts/modules/tabs.test.ts +79 -12
  226. package/assets/ts/modules/test-dom.ts +5 -0
  227. package/assets/ts/modules/testimonial.test.ts +45 -6
  228. package/assets/ts/modules/videos.test.ts +74 -14
  229. package/dist/components.es.js +25 -25
  230. package/dist/components.umd.js +170 -163
  231. package/package.json +1 -1
  232. package/assets/js/modules/carousel.js +0 -214
  233. package/assets/js/modules/carousel.test.js +0 -18
  234. package/assets/ts/modules/carousel.test.ts +0 -27
  235. package/assets/ts/modules/carousel.ts +0 -301
@@ -16,34 +16,42 @@ export const cardHTML = `<div class="wrapper">
16
16
  </div>
17
17
  </div>`;
18
18
 
19
- export const setupCard = (cardComponent: any): void => {
19
+ const getCardPart = <T extends Element>(cardComponent: HTMLElement, selector: string): T | null =>
20
+ cardComponent.shadowRoot?.querySelector<T>(selector) || null;
21
+
22
+ export const setupCard = (cardComponent: HTMLElement): void => {
20
23
  cardComponent.classList.add('card');
21
- const cardHead = cardComponent.shadowRoot.querySelector('.card__head');
22
- const cardBody = cardComponent.shadowRoot.querySelector('.card__body');
24
+ const cardHead = getCardPart<HTMLDivElement>(cardComponent, '.card__head');
25
+ const cardBody = getCardPart<HTMLDivElement>(cardComponent, '.card__body');
26
+ const cardBadges = getCardPart<HTMLDivElement>(cardComponent, '.card__badges');
23
27
 
24
28
  if (cardComponent.hasAttribute('data-image')) {
25
- cardHead.innerHTML += `<img src="${cardComponent.getAttribute('data-image')}" alt="" loading="lazy" part="image" />`;
29
+ cardHead?.insertAdjacentHTML(
30
+ 'beforeend',
31
+ `<img src="${cardComponent.getAttribute('data-image') || ''}" alt="" loading="lazy" part="image" />`
32
+ );
26
33
  }
27
34
 
28
35
  // Inset the HTML for the data total or icon fallback
29
36
  if (cardComponent.hasAttribute('data-total')) {
30
37
 
31
- if(!cardBody?.querySelector('.card__total'))
38
+ const cardTotal = cardBody?.querySelector<HTMLDivElement>('.card__total');
39
+
40
+ if(!cardTotal)
32
41
  cardBody.insertAdjacentHTML(
33
42
  'beforeend',
34
- `<div class="card__total">${cardComponent.getAttribute('data-total')}</div>`
43
+ `<div class="card__total">${cardComponent.getAttribute('data-total') || ''}</div>`
35
44
  );
36
45
  else {
37
- const cardTotal = cardBody?.querySelector('.card__total');
38
- if (cardTotal) cardTotal.innerHTML = cardComponent.getAttribute('data-total');
46
+ cardTotal.innerHTML = cardComponent.getAttribute('data-total') || '';
39
47
  }
40
48
  } else if (cardComponent.querySelector('[slot="total-icon"]')) {
41
- cardBody.insertAdjacentHTML('beforeend', `<div class="card__total"><slot name="total-icon"></slot></div>`);
49
+ cardBody?.insertAdjacentHTML('beforeend', `<div class="card__total"><slot name="total-icon"></slot></div>`);
42
50
  }
43
51
 
44
52
  if (!cardComponent.querySelector('[slot="badges"]')) {
45
- cardComponent.shadowRoot.querySelector('.card__badges').classList.add('empty');
53
+ cardBadges?.classList.add('empty');
46
54
  } else {
47
- cardComponent.shadowRoot.querySelector('.card__badges').classList.remove('empty');
55
+ cardBadges?.classList.remove('empty');
48
56
  }
49
57
  };
@@ -1,24 +1,96 @@
1
1
  import { describe, expect, it } from './test.ts';
2
2
  import { createElement, installTestDom } from './test-dom.ts';
3
3
  import { append } from './test-utils.ts';
4
- import { transformButtons } from './content.ts';
4
+ import { createTitle, loadComponents, replaceShortcode, transformButtons, transformElement } from './content.ts';
5
5
 
6
- const { document } = installTestDom();
6
+ installTestDom();
7
+
8
+ type TestAttribute = {
9
+ name: string;
10
+ value: string;
11
+ };
12
+
13
+ type AttributeComponent = {
14
+ attributes: TestAttribute[];
15
+ getAttribute: (name: string) => string | null;
16
+ hasAttribute: (name: string) => boolean;
17
+ };
18
+
19
+ const createAttributeComponent = (attributes: TestAttribute[]): AttributeComponent => ({
20
+ attributes,
21
+ getAttribute(name: string): string | null {
22
+ const attribute = attributes.find((attr) => attr.name === name);
23
+ return attribute ? attribute.value : null;
24
+ },
25
+ hasAttribute(name: string): boolean {
26
+ return attributes.some((attr) => attr.name === name);
27
+ },
28
+ });
7
29
 
8
30
  describe('Content module', () => {
31
+ it('replaces WordPress shortcode paragraphs with loading placeholders', () => {
32
+ const content = '<p>Intro</p><p>[search-learning-articles]</p><p>[search-contacts]</p>';
33
+ const transformed = replaceShortcode(content);
34
+
35
+ expect(transformed.includes('<p>Intro</p>'));
36
+ expect(transformed.includes('data-shortcode="search-learning-articles"'));
37
+ expect(transformed.includes('data-shortcode="search-contacts"'));
38
+ expect(!transformed.includes('<p>[search-learning-articles]</p>'));
39
+ expect(!transformed.includes('<p>[search-contacts]</p>'));
40
+ });
41
+
42
+ it('creates configured titles and skips missing titles', () => {
43
+ const component = createElement('iam-content', {
44
+ dataTitleTag: 'h2',
45
+ dataTitleClass: 'bg-light',
46
+ });
47
+
48
+ expect(createTitle(component, 'Latest news') === '<h2 class="bg-light iam-content--title">Latest news</h2>');
49
+ expect(createTitle(component, '') === '');
50
+ expect(createTitle(createElement('iam-content'), 'Latest news') === '');
51
+ });
52
+
53
+ it('wraps rendered content in the requested transform element', () => {
54
+ const component = createAttributeComponent([
55
+ { name: 'data-transform', value: 'article' },
56
+ { name: 'data-url', value: '/wp-json/wp/v2/pages/1' },
57
+ { name: 'class', value: 'content-panel' },
58
+ ]);
59
+
60
+ const transformed = transformElement(component, '<h2>Heading</h2>', '<p>Body</p>');
61
+
62
+ expect(transformed.startsWith('<article '));
63
+ expect(transformed.includes('data-transform="article"'));
64
+ expect(transformed.includes('data-url="/wp-json/wp/v2/pages/1"'));
65
+ expect(transformed.includes('class="content-panel"'));
66
+ expect(transformed.includes('<h2>Heading</h2><p>Body</p>'));
67
+ expect(transformed.endsWith('</article>'));
68
+ });
69
+
9
70
  it('transforms WordPress button wrappers into direct links', () => {
10
- const parent = createElement('div');
11
71
  const buttons = createElement('div', { class: 'wp-block-buttons' });
12
- const button = createElement('div', { class: 'btn btn-primary wp-block-button' });
13
- const link = createElement('a', { href: '/test' }, 'Open');
14
- append(button, link);
15
- append(buttons, button);
16
- append(parent, buttons);
17
- append(document.body, parent);
72
+ const primaryButton = createElement('div', { class: 'btn btn-primary wp-block-button' });
73
+ const secondaryButton = createElement('div', { class: 'btn btn-secondary wp-block-button' });
74
+ const primaryLink = createElement('a', { href: '/primary' }, 'Primary');
75
+ const secondaryLink = createElement('a', { href: '/secondary' }, 'Secondary');
76
+ append(primaryButton, primaryLink);
77
+ append(secondaryButton, secondaryLink);
78
+ append(buttons, primaryButton, secondaryButton);
79
+
80
+ const fragment = transformButtons(buttons);
81
+
82
+ expect(fragment.children.length === 2);
83
+ expect(fragment.children[0] === primaryLink);
84
+ expect(fragment.children[1] === secondaryLink);
85
+ expect(primaryLink.getAttribute('class') === 'btn btn-primary wp-block-button');
86
+ expect(secondaryLink.getAttribute('class') === 'btn btn-secondary wp-block-button');
87
+ });
88
+
89
+ it('does not load component bundles when content contains no supported custom elements', () => {
90
+ const component = createElement('iam-content');
18
91
 
19
- transformButtons();
92
+ loadComponents(component);
20
93
 
21
- expect(link.getAttribute('class') === 'btn btn-primary wp-block-button');
22
- expect(parent.children[0].localName === 'fragment');
94
+ expect(component.getElementsByTagName('iam-card').length === 0);
23
95
  });
24
96
  });
@@ -1,17 +1,64 @@
1
- export const transformButtons = (component):void => {
2
1
 
3
- Array.from(document.querySelectorAll('.wp-block-buttons')).forEach((buttons) => {
4
2
 
5
- const fragment = document.createDocumentFragment();
3
+ export const loadComponents = (component):void => {
6
4
 
7
- Array.from(buttons.querySelectorAll('.wp-block-button')).forEach((element) => {
5
+ const components = ['skeleton','bone','carousel', 'card', 'banner', 'notification'];
6
+ const assetLocation = document.body.hasAttribute('data-assets-location')
7
+ ? document.body.getAttribute('data-assets-location')
8
+ : '/assets';
8
9
 
9
- const link = element.querySelector('a');
10
- link.setAttribute('class',element.getAttribute('class'));
10
+ components.forEach((loadComponent) => {
11
11
 
12
- fragment.appendChild(link);
13
- });
12
+ if (component.getElementsByTagName(`iam-${loadComponent}`).length === 0) return;
14
13
 
15
- buttons.parentNode.replaceChild(fragment, buttons);
14
+ import(/*! @vite-ignore */ `${assetLocation}/js/components/${loadComponent}/${loadComponent}.component.min.js`)
15
+ .then((module) => {
16
+ if (!window.customElements.get(`iam-${loadComponent}`))
17
+ window.customElements.define(`iam-${loadComponent}`, module.default);
18
+ })
19
+ .catch((err) => {
20
+ console.log(err.message);
21
+ });
16
22
  });
17
23
  }
24
+
25
+ export const replaceShortcode = (content):string => {
26
+
27
+ return content.replaceAll(/<p>\[([^\]]+)\]<\/p>/g, "<span data-shortcode=\"$1\"><iam-skeleton><iam-bone class=\"search\"></iam-bone></iam-skeleton></span>");
28
+ }
29
+
30
+ export const createTitle = (component, title):string => {
31
+
32
+ if (component.hasAttribute('data-title-tag') && title)
33
+ return `<${component.getAttribute('data-title-tag')} class="${component.getAttribute('data-title-class')} iam-content--title">${title}</${component.getAttribute('data-title-tag')}>`;
34
+
35
+ return '';
36
+ }
37
+
38
+ export const transformElement = (component,renderedTitle,renderedContent): string => {
39
+
40
+ const transform = component.getAttribute('data-transform');
41
+
42
+ let elementAttributes = '';
43
+
44
+ for (const attr of component.attributes) {
45
+ elementAttributes += `${attr.name}="${attr.value}" `;
46
+ }
47
+
48
+ return `<${transform} ${elementAttributes}>${renderedTitle+renderedContent}</${transform}>`;
49
+ }
50
+
51
+ export const transformButtons = (buttons): DocumentFragment => {
52
+
53
+ const fragment = document.createDocumentFragment();
54
+
55
+ Array.from(buttons.querySelectorAll('.wp-block-button')).forEach((element) => {
56
+
57
+ const link = element.querySelector('a');
58
+ link.setAttribute('class',element.getAttribute('class'));
59
+
60
+ fragment.appendChild(link);
61
+ });
62
+
63
+ return fragment;
64
+ }
@@ -1,12 +1,8 @@
1
- type WindowWithDataLayer = Window & {
2
- dataLayer: Record<string, any>[];
3
- };
4
-
5
- declare const window: WindowWithDataLayer;
1
+ const dataLayerWindow = window as WindowWithDataLayer;
6
2
 
7
3
  function createDataLayer(): void {
8
- window.dataLayer = window.dataLayer || [];
9
- window.dataLayer.push({
4
+ dataLayerWindow.dataLayer = dataLayerWindow.dataLayer || [];
5
+ dataLayerWindow.dataLayer.push({
10
6
  event: 'Pageview',
11
7
  pageTitle: document.title,
12
8
  });
@@ -15,7 +11,7 @@ function createDataLayer(): void {
15
11
  const target = (event.target as HTMLElement).closest<HTMLElement>('[open] summary');
16
12
 
17
13
  if (target) {
18
- window.dataLayer.push({
14
+ dataLayerWindow.dataLayer.push({
19
15
  event: 'closeDetails',
20
16
  detailsTitle: target.textContent || '',
21
17
  });
@@ -25,14 +21,14 @@ function createDataLayer(): void {
25
21
  const button = (event.target as HTMLElement).closest<HTMLButtonElement>('button');
26
22
 
27
23
  if (summary) {
28
- window.dataLayer.push({
24
+ dataLayerWindow.dataLayer.push({
29
25
  event: 'openDetails',
30
26
  detailsTitle: summary.textContent || '',
31
27
  });
32
28
  }
33
29
 
34
30
  if (link) {
35
- window.dataLayer.push({
31
+ dataLayerWindow.dataLayer.push({
36
32
  event: 'linkClicked',
37
33
  linkText: link.hasAttribute('title') ? link.getAttribute('title') || '' : link.textContent || '',
38
34
  class: link.hasAttribute('class') ? link.getAttribute('class') || '' : '',
@@ -41,7 +37,7 @@ function createDataLayer(): void {
41
37
  }
42
38
 
43
39
  if (button) {
44
- window.dataLayer.push({
40
+ dataLayerWindow.dataLayer.push({
45
41
  event: 'buttonClicked',
46
42
  buttonText: button.textContent || '',
47
43
  class: button.hasAttribute('class') ? button.getAttribute('class') || '' : '',
@@ -25,8 +25,6 @@ export const searchAjax = async (component, search, callback): any => {
25
25
  const ajaxURL = component.getAttribute('data-url');
26
26
  const firstInput = component.querySelector('input');
27
27
 
28
- console.log(firstInput);
29
-
30
28
  const inputType = firstInput && firstInput.hasAttribute('type') ? firstInput.getAttribute('type') : 'checkbox';
31
29
  let inputName = firstInput && firstInput.hasAttribute('name') ? firstInput.getAttribute('name') : 'tags';
32
30
 
@@ -0,0 +1,183 @@
1
+ import { describe, expect, it } from './test.ts';
2
+ import { createElement, installTestDom } from './test-dom.ts';
3
+ import { append } from './test-utils.ts';
4
+ import {
5
+ checkConditions,
6
+ disabledIf,
7
+ emptyIf,
8
+ enabledIf,
9
+ getCheckboxLimit,
10
+ hideIf,
11
+ isFormValid,
12
+ limitCheckboxes,
13
+ readonlyIf,
14
+ requiredIf,
15
+ showIf,
16
+ writeIf,
17
+ } from './form.ts';
18
+
19
+ const { window } = installTestDom();
20
+
21
+ if (typeof globalThis.CustomEvent === 'undefined') {
22
+ globalThis.CustomEvent = class extends Event {
23
+ detail;
24
+
25
+ constructor(type, options = {}) {
26
+ super(type, options);
27
+ this.detail = options.detail;
28
+ }
29
+ };
30
+ }
31
+
32
+ const condition = (id, equals) => JSON.stringify([{ if: id, equals }]);
33
+
34
+ const createChangeEvent = (target) => {
35
+ const event = new Event('change', { bubbles: true, cancelable: true });
36
+ Object.defineProperty(event, 'target', { value: target });
37
+
38
+ return event;
39
+ };
40
+
41
+ describe('Form module', () => {
42
+ it('checks form validity against invalid fields, weak passwords and required multiselects', () => {
43
+ const form = createElement('form');
44
+ const originalQuerySelector = form.querySelector.bind(form);
45
+
46
+ form.querySelector = (selector) => (selector === ':invalid' ? createElement('input') : originalQuerySelector(selector));
47
+
48
+ expect(!isFormValid(form));
49
+
50
+ form.querySelector = originalQuerySelector;
51
+ append(form, createElement('div', { class: 'pwd-checker', dataStrength: '1' }));
52
+
53
+ expect(!isFormValid(form));
54
+
55
+ form.children = [];
56
+ append(form, createElement('iam-multiselect', { dataError: 'true', dataIsRequired: 'true' }));
57
+
58
+ expect(!isFormValid(form));
59
+
60
+ form.children = [];
61
+
62
+ expect(isFormValid(form));
63
+ });
64
+
65
+ it('evaluates JSON conditions against form control values', () => {
66
+ const form = createElement('form');
67
+ append(form, createElement('input', { id: 'status', value: 'active' }));
68
+
69
+ expect(checkConditions(condition('status', 'active'), form));
70
+ expect(!checkConditions(condition('status', 'archived'), form));
71
+ });
72
+
73
+ it('applies visibility conditional helpers', () => {
74
+ const form = createElement('form');
75
+ const status = createElement('input', { id: 'status', value: 'active' });
76
+ const shown = createElement('div', { dataShowIf: condition('status', 'active') });
77
+ const hidden = createElement('div', { dataHideIf: condition('status', 'active') });
78
+ append(form, status, shown, hidden);
79
+
80
+ showIf(form);
81
+ hideIf(form);
82
+
83
+ expect(!shown.classList.contains('d-none'));
84
+ expect(hidden.classList.contains('d-none'));
85
+
86
+ status.value = 'archived';
87
+ showIf(form);
88
+ hideIf(form);
89
+
90
+ expect(shown.classList.contains('d-none'));
91
+ expect(!hidden.classList.contains('d-none'));
92
+ });
93
+
94
+ it('applies enabled, disabled, required and readonly conditional helpers', () => {
95
+ const form = createElement('form');
96
+ const status = createElement('input', { id: 'status', value: 'active' });
97
+ const disabled = createElement('input', { dataDisabledIf: condition('status', 'active') });
98
+ const enabled = createElement('input', { dataEnabledIf: condition('status', 'active') });
99
+ const required = createElement('input', { dataRequiredIf: condition('status', 'active') });
100
+ const readonly = createElement('input', { dataReadonlyIf: condition('status', 'active') });
101
+ const writable = createElement('input', { dataWriteIf: condition('status', 'active') });
102
+ append(form, status, disabled, enabled, required, readonly, writable);
103
+
104
+ disabledIf(form);
105
+ enabledIf(form);
106
+ requiredIf(form);
107
+ readonlyIf(form);
108
+ writeIf(form);
109
+
110
+ expect(disabled.hasAttribute('disabled'));
111
+ expect(!enabled.hasAttribute('disabled'));
112
+ expect(required.hasAttribute('required'));
113
+ expect(readonly.hasAttribute('readonly'));
114
+ expect(!writable.hasAttribute('readonly'));
115
+
116
+ status.value = 'archived';
117
+ disabledIf(form);
118
+ enabledIf(form);
119
+ requiredIf(form);
120
+ readonlyIf(form);
121
+ writeIf(form);
122
+
123
+ expect(!disabled.hasAttribute('disabled'));
124
+ expect(enabled.hasAttribute('disabled'));
125
+ expect(!required.hasAttribute('required'));
126
+ expect(!readonly.hasAttribute('readonly'));
127
+ expect(writable.hasAttribute('readonly'));
128
+ });
129
+
130
+ it('empties form controls when conditions match', () => {
131
+ const form = createElement('form');
132
+ const status = createElement('input', { id: 'status', value: 'clear' });
133
+ const target = createElement('input', { dataEmptyIf: condition('status', 'clear'), value: 'remove me' });
134
+ append(form, status, target);
135
+
136
+ emptyIf(form);
137
+
138
+ expect(target.value === '');
139
+ });
140
+
141
+ it('resolves checkbox limits with a valid positive fallback', () => {
142
+ expect(getCheckboxLimit(createElement('div', { dataCheckboxLimit: '2' })) === 2);
143
+ expect(getCheckboxLimit(createElement('div', { dataCheckboxLimit: '0' })) === 10);
144
+ expect(getCheckboxLimit(createElement('div', { dataCheckboxLimit: 'nope' })) === 10);
145
+ });
146
+
147
+ it('disables unchecked checkboxes and emits analytics when a limit is reached', () => {
148
+ window.dataLayer = [];
149
+ const form = createElement('form');
150
+ const group = createElement('fieldset', { dataCheckboxLimit: '2', id: 'topics' });
151
+ const first = createElement('input', { checked: true, type: 'checkbox' });
152
+ const second = createElement('input', { checked: true, type: 'checkbox' });
153
+ const third = createElement('input', { type: 'checkbox' });
154
+ let eventDetail;
155
+ form.addEventListener('checkbox-limit-reached', (event) => {
156
+ eventDetail = event.detail;
157
+ });
158
+ append(group, first, second, third);
159
+ append(form, group);
160
+
161
+ limitCheckboxes(createChangeEvent(second), form);
162
+
163
+ expect(third.hasAttribute('disabled'));
164
+ expect(eventDetail.element === '#topics');
165
+ expect(eventDetail.limit === 2);
166
+ expect(window.dataLayer[0].event === 'checkbox-limit-reached');
167
+ expect(window.dataLayer[0].element === '#topics');
168
+ });
169
+
170
+ it('prevents checking beyond the configured checkbox limit', () => {
171
+ const form = createElement('form');
172
+ const group = createElement('fieldset', { dataCheckboxLimit: '1' });
173
+ const first = createElement('input', { checked: true, type: 'checkbox' });
174
+ const second = createElement('input', { checked: true, type: 'checkbox' });
175
+ append(group, first, second);
176
+ append(form, group);
177
+
178
+ limitCheckboxes(createChangeEvent(second), form);
179
+
180
+ expect(first.checked);
181
+ expect(!second.checked);
182
+ });
183
+ });