@iamproperty/components 7.8.2--beta4 → 7.8.2--beta6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/components/actionbar.component.css +1 -1
- package/assets/css/components/actionbar.component.css.map +1 -1
- package/assets/css/components/calendar.component.css +1 -1
- package/assets/css/components/calendar.component.css.map +1 -1
- package/assets/css/components/card.component.css +1 -1
- package/assets/css/components/card.component.css.map +1 -1
- package/assets/css/components/carousel.config.css +1 -1
- package/assets/css/components/carousel.config.css.map +1 -1
- package/assets/css/components/modal.component.css +1 -1
- package/assets/css/components/modal.component.css.map +1 -1
- package/assets/css/components/multi-step-modal.component.css +1 -1
- package/assets/css/components/multi-step-modal.component.css.map +1 -1
- package/assets/css/components/nav.component.css +1 -1
- package/assets/css/components/nav.component.css.map +1 -1
- package/assets/css/components/nav.global.css +1 -1
- package/assets/css/components/nav.global.css.map +1 -1
- package/assets/css/components/notification.global.css +1 -1
- package/assets/css/components/notification.global.css.map +1 -1
- package/assets/css/components/std-nav-standalone.component.css +1 -1
- package/assets/css/components/std-nav-standalone.component.css.map +1 -1
- package/assets/css/components/video-card.component.css +1 -1
- package/assets/css/components/video-card.component.css.map +1 -1
- package/assets/css/components/video-modal.component.css +1 -1
- package/assets/css/components/video-modal.component.css.map +1 -1
- package/assets/css/core.min.css +1 -1
- package/assets/css/core.min.css.map +1 -1
- package/assets/css/elements/dialog.css +1 -1
- package/assets/css/elements/dialog.css.map +1 -1
- package/assets/css/style.min.css +1 -1
- package/assets/css/style.min.css.map +1 -1
- package/assets/js/components/accordion/accordion.component.min.js +1 -1
- package/assets/js/components/actionbar/actionbar.component.min.js +3 -3
- package/assets/js/components/address-lookup/address-lookup.component.min.js +2 -2
- package/assets/js/components/address-lookup/address-lookup.component.min.js.map +1 -1
- package/assets/js/components/advanced-select/advanced-select.component.min.js +1 -1
- package/assets/js/components/applied-filters/applied-filters.component.min.js +1 -1
- package/assets/js/components/banner/banner.component.min.js +1 -1
- package/assets/js/components/barchart/barchart.component.min.js +1 -1
- package/assets/js/components/bento-grid/bento-grid.component.min.js +1 -1
- package/assets/js/components/bone/bone.component.min.js +1 -1
- package/assets/js/components/button/button.component.min.js +1 -1
- package/assets/js/components/calendar/calendar.component.min.js +2 -2
- package/assets/js/components/card/card.component.min.js +6 -6
- package/assets/js/components/card/card.component.min.js.map +1 -1
- package/assets/js/components/carousel/carousel.component.min.js +1 -1
- package/assets/js/components/collapsible-side/collapsible-side.component.min.js +1 -1
- package/assets/js/components/config/config.component.min.js +2 -2
- package/assets/js/components/config/config.component.min.js.map +1 -1
- package/assets/js/components/content/content.component.min.js +1 -1
- package/assets/js/components/darkmode/darkmode.component.min.js +1 -1
- package/assets/js/components/doughnutchart/doughnutchart.component.min.js +1 -1
- package/assets/js/components/fileupload/fileupload.component.min.js +1 -1
- package/assets/js/components/filter-card/filter-card.component.min.js +2 -2
- package/assets/js/components/filter-card/filter-card.component.min.js.map +1 -1
- package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
- package/assets/js/components/form/form.component.js +42 -151
- package/assets/js/components/form/form.component.min.js +3 -3
- package/assets/js/components/form/form.component.min.js.map +1 -1
- package/assets/js/components/header/header.component.min.js +1 -1
- package/assets/js/components/inline-edit/inline-edit.component.min.js +2 -2
- package/assets/js/components/inline-edit/inline-edit.component.min.js.map +1 -1
- package/assets/js/components/input/input.component.min.js +1 -1
- package/assets/js/components/input-range/input-range.component.min.js +1 -1
- package/assets/js/components/marketing/marketing.component.min.js +1 -1
- package/assets/js/components/menu/menu.component.min.js +1 -1
- package/assets/js/components/milestone/milestone.component.min.js +1 -1
- package/assets/js/components/milestone-group/milestone-group.component.min.js +1 -1
- package/assets/js/components/modal/modal.component.js +16 -11
- package/assets/js/components/modal/modal.component.min.js +7 -7
- package/assets/js/components/modal/modal.component.min.js.map +1 -1
- package/assets/js/components/multi-step/multi-step.component.min.js +2 -2
- package/assets/js/components/multi-step/multi-step.component.min.js.map +1 -1
- package/assets/js/components/multi-step-modal/multi-step-modal.component.min.js +4 -4
- package/assets/js/components/multi-step-modal/multi-step-modal.component.min.js.map +1 -1
- package/assets/js/components/multiselect/multiselect.component.min.js +2 -2
- package/assets/js/components/multiselect/multiselect.component.min.js.map +1 -1
- package/assets/js/components/nav/nav.component.js +88 -79
- package/assets/js/components/nav/nav.component.min.js +8 -8
- package/assets/js/components/nav/nav.component.min.js.map +1 -1
- package/assets/js/components/notification/notification.component.min.js +2 -2
- package/assets/js/components/pagination/pagination.component.min.js +1 -1
- package/assets/js/components/password/password.component.min.js +1 -1
- package/assets/js/components/popover/popover.component.min.js +1 -1
- package/assets/js/components/rank/rank.component.min.js +1 -1
- package/assets/js/components/rankings/rankings.component.min.js +1 -1
- package/assets/js/components/rating/rating.component.min.js +1 -1
- package/assets/js/components/record-card/record-card.component.min.js +2 -2
- package/assets/js/components/record-card/record-card.component.min.js.map +1 -1
- package/assets/js/components/search/search.component.js +2 -1
- package/assets/js/components/search/search.component.min.js +3 -3
- package/assets/js/components/search/search.component.min.js.map +1 -1
- package/assets/js/components/skeleton/skeleton.component.min.js +1 -1
- package/assets/js/components/slider/slider.component.min.js +1 -1
- package/assets/js/components/split-button/split-button.component.min.js +1 -1
- package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js +3 -3
- package/assets/js/components/std-address-lookup/std-address-lookup.component.min.js.map +1 -1
- package/assets/js/components/std-nav/std-nav.component.js +2 -0
- package/assets/js/components/std-nav/std-nav.component.min.js +12 -12
- package/assets/js/components/std-nav/std-nav.component.min.js.map +1 -1
- package/assets/js/components/std-nav-standalone/std-nav-standalone.component.min.js +2 -2
- package/assets/js/components/table/table.component.min.js +1 -1
- package/assets/js/components/table-ajax/table-ajax.component.min.js +1 -1
- package/assets/js/components/table-basic/table-basic.component.min.js +1 -1
- package/assets/js/components/table-no-submit/table-no-submit.component.min.js +1 -1
- package/assets/js/components/table-submit/table-submit.component.min.js +1 -1
- package/assets/js/components/tabs/tabs.component.min.js +1 -1
- package/assets/js/components/tag/tag.component.min.js +2 -2
- package/assets/js/components/tag/tag.component.min.js.map +1 -1
- package/assets/js/components/tooltip/tooltip.component.min.js +1 -1
- package/assets/js/components/video/video.component.min.js +1 -1
- package/assets/js/components/video-card/video-card.component.min.js +6 -6
- package/assets/js/components/video-card/video-card.component.min.js.map +1 -1
- package/assets/js/components/video-modal/video-modal.component.min.js +5 -5
- package/assets/js/components/word-count/word-count.component.min.js +1 -1
- package/assets/js/modules/card.module.js +1 -1
- package/assets/js/modules/form.js +129 -0
- package/assets/js/modules/form.test.js +132 -0
- package/assets/js/modules/test-dom.js +5 -0
- package/assets/js/scripts.bundle.js +1 -1
- package/assets/js/scripts.bundle.min.js +1 -1
- package/assets/sass/_utilities.scss +1 -0
- package/assets/sass/components/carousel.config.scss +5 -0
- package/assets/sass/components/modal.component.scss +5 -1
- package/assets/sass/components/nav.global.scss +0 -10
- package/assets/sass/components/notification.global.scss +8 -0
- package/assets/sass/elements/dialog.scss +43 -0
- package/assets/sass/foundations/colours.scss +15 -24
- package/assets/sass/foundations/reboot.scss +4 -0
- package/assets/sass/utilities/wordpress.css +7 -0
- package/assets/ts/components/form/form.component.ts +54 -213
- package/assets/ts/components/modal/modal.component.ts +27 -19
- package/assets/ts/components/nav/nav.component.ts +107 -95
- package/assets/ts/components/search/search.component.ts +5 -1
- package/assets/ts/components/std-nav/std-nav.component.ts +3 -1
- package/assets/ts/modules/card.module.ts +1 -1
- package/assets/ts/modules/form.test.ts +183 -0
- package/assets/ts/modules/form.ts +210 -0
- package/assets/ts/modules/test-dom.ts +5 -0
- package/dist/components.es.js +2662 -1246
- package/dist/components.umd.js +372 -372
- package/package.json +5 -5
|
@@ -17,7 +17,7 @@ class iamModal extends HTMLElement {
|
|
|
17
17
|
template.innerHTML = `
|
|
18
18
|
<style>
|
|
19
19
|
${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
${loadCSS}
|
|
22
22
|
</style>
|
|
23
23
|
<link rel="stylesheet" href="https://kit.fontawesome.com/8bd0fca975.css" crossorigin="anonymous" />
|
|
@@ -41,6 +41,7 @@ class iamModal extends HTMLElement {
|
|
|
41
41
|
|
|
42
42
|
connectedCallback(): void {
|
|
43
43
|
|
|
44
|
+
const hasDialogParent = this.closest('dialog[id]');
|
|
44
45
|
const originalDialog = this.querySelector('dialog');
|
|
45
46
|
|
|
46
47
|
const id = this.hasAttribute('id') ? this.getAttribute('id') : originalDialog?.getAttribute('id');
|
|
@@ -50,6 +51,10 @@ class iamModal extends HTMLElement {
|
|
|
50
51
|
const agreedButton = this.querySelector('button[slot="agreed-button"]') ? this.querySelector('button[slot="agreed-button"]') : this.shadowRoot?.querySelector('[data-agreed]');
|
|
51
52
|
const modalType = this.hasAttribute('data-type') ? this.getAttribute('data-type') : 'passive';
|
|
52
53
|
|
|
54
|
+
|
|
55
|
+
if(hasDialogParent)
|
|
56
|
+
this.classList.add('has-parent-dialog');
|
|
57
|
+
|
|
53
58
|
const agreed = (close = true) => {
|
|
54
59
|
const agreedEvent = new CustomEvent('agreed', {
|
|
55
60
|
detail: { modalId: id },
|
|
@@ -62,20 +67,20 @@ class iamModal extends HTMLElement {
|
|
|
62
67
|
}
|
|
63
68
|
|
|
64
69
|
document.addEventListener('click', (e) => {
|
|
65
|
-
|
|
70
|
+
|
|
66
71
|
if(e.target.matches(`[command="show-modal"][commandfor="${id}"]`) || e.target.matches(`[data-modal="${id}"]`)){
|
|
67
72
|
openModal(this);
|
|
68
73
|
}
|
|
69
74
|
});
|
|
70
75
|
|
|
71
76
|
document.addEventListener('click', (e) => {
|
|
72
|
-
|
|
77
|
+
|
|
73
78
|
if(e.target.matches(`[command="close"][commandfor="${id}"]`)){
|
|
74
79
|
closeModal(this);
|
|
75
80
|
}
|
|
76
81
|
});
|
|
77
|
-
|
|
78
|
-
// Disable the original event
|
|
82
|
+
|
|
83
|
+
// Disable the original event
|
|
79
84
|
originalDialog?.addEventListener('command', (e) => {
|
|
80
85
|
|
|
81
86
|
if (event.command == "show-modal") {
|
|
@@ -103,7 +108,7 @@ class iamModal extends HTMLElement {
|
|
|
103
108
|
if(originalDialog) {
|
|
104
109
|
Array.from(originalDialog?.querySelectorAll('[slot]')).forEach((element) => {
|
|
105
110
|
this.moveBefore(element, originalDialog);
|
|
106
|
-
});
|
|
111
|
+
});
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
closeButton?.addEventListener('click', () => {
|
|
@@ -118,30 +123,33 @@ class iamModal extends HTMLElement {
|
|
|
118
123
|
|
|
119
124
|
agreed();
|
|
120
125
|
});
|
|
121
|
-
|
|
126
|
+
|
|
122
127
|
|
|
123
128
|
this.addEventListener('close-modal', () => {
|
|
124
129
|
closeModal(this);
|
|
125
130
|
});
|
|
126
131
|
|
|
127
|
-
// Hijack the default form submission
|
|
128
|
-
|
|
132
|
+
// Hijack the default form submission
|
|
133
|
+
if(!hasDialogParent){
|
|
134
|
+
originalDialog?.addEventListener('submit', (e) => {
|
|
135
|
+
|
|
136
|
+
if(e.submitter && e.submitter.hasAttribute('formmethod') && e.submitter.getAttribute('formmethod') =="dialog"){
|
|
137
|
+
|
|
138
|
+
closeModal(this);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
agreed(false);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
129
145
|
|
|
130
|
-
if(e.submitter && e.submitter.hasAttribute('formmethod') && e.submitter.getAttribute('formmethod') =="dialog"){
|
|
131
|
-
|
|
132
|
-
closeModal(this);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
agreed(false);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
146
|
|
|
139
147
|
Array.from(this.querySelectorAll('button[type="submit"]')).forEach((button)=> {
|
|
140
148
|
|
|
141
149
|
button.addEventListener('click', (e) => {
|
|
142
150
|
|
|
143
151
|
if(!button.closest('form') && !button.hasAttribute('formmethod')){
|
|
144
|
-
|
|
152
|
+
|
|
145
153
|
agreed();
|
|
146
154
|
}
|
|
147
155
|
});
|
|
@@ -179,7 +187,7 @@ class iamModal extends HTMLElement {
|
|
|
179
187
|
</i>`
|
|
180
188
|
);
|
|
181
189
|
}
|
|
182
|
-
|
|
190
|
+
|
|
183
191
|
}
|
|
184
192
|
}
|
|
185
193
|
|
|
@@ -32,7 +32,7 @@ class iamNav extends HTMLElement {
|
|
|
32
32
|
|
|
33
33
|
<div class="menu__outer">
|
|
34
34
|
<div class="menu closed">
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
<div class="menu__primary">
|
|
37
37
|
<slot></slot>
|
|
38
38
|
<slot name="dual"></slot>
|
|
@@ -46,7 +46,7 @@ class iamNav extends HTMLElement {
|
|
|
46
46
|
</div>
|
|
47
47
|
</div>
|
|
48
48
|
<slot name="menus"></slot>
|
|
49
|
-
</div>
|
|
49
|
+
</div>
|
|
50
50
|
</div>
|
|
51
51
|
<div class="backdrop" part="backdrop"></div>
|
|
52
52
|
`;
|
|
@@ -73,107 +73,119 @@ class iamNav extends HTMLElement {
|
|
|
73
73
|
const buttonsHolder = this.shadowRoot.querySelector('.buttons-holder');
|
|
74
74
|
|
|
75
75
|
// Check the content
|
|
76
|
-
|
|
77
|
-
const tagname = element.tagName;
|
|
78
|
-
|
|
79
|
-
switch (tagname) {
|
|
80
|
-
case 'BUTTON':
|
|
81
|
-
if (!element.hasAttribute('slot')) {
|
|
82
|
-
element.setAttribute('slot', 'actions');
|
|
83
|
-
menu.classList.add('has-actions');
|
|
84
|
-
}
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
76
|
+
const createNavMenu = (component) => {
|
|
87
77
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const button = document.createElement('button');
|
|
100
|
-
button.setAttribute('slot', title);
|
|
101
|
-
button.classList.add('btn-menu');
|
|
102
|
-
button.setAttribute('part', 'btn-menu');
|
|
103
|
-
button.innerHTML = `<span class="btn btn-primary"><span>${title}</span><i class="${iconClass}"></i><i class="fa-regular fa-xmark-large"></i></span>`;
|
|
104
|
-
buttonsHolder.insertAdjacentElement('beforeend', button);
|
|
105
|
-
|
|
106
|
-
const mdButton = button.querySelector('.btn-primary');
|
|
107
|
-
|
|
108
|
-
// Make sure the menu is added to the right part of the component
|
|
109
|
-
element.setAttribute('slot', 'menus');
|
|
110
|
-
|
|
111
|
-
// If open we need to make sure the main mobile menu is closed, the new button has the right state and the backdrop is shown
|
|
112
|
-
if (element.classList.contains('open')) {
|
|
113
|
-
button.setAttribute('aria-expanded', true);
|
|
114
|
-
mdButton.classList.toggle('active');
|
|
115
|
-
iamNav.classList.add('open');
|
|
116
|
-
backdrop.classList.add('show');
|
|
117
|
-
} else {
|
|
118
|
-
element.classList.add('closed'); // closed class is added to prevent the elements being tabbed into, this causes visual issues
|
|
78
|
+
buttonsHolder.innerHTML = '';
|
|
79
|
+
component.querySelectorAll(':scope > *').forEach(function (element) {
|
|
80
|
+
const tagname = element.tagName;
|
|
81
|
+
|
|
82
|
+
switch (tagname) {
|
|
83
|
+
case 'BUTTON':
|
|
84
|
+
if (!element.hasAttribute('slot')) {
|
|
85
|
+
element.setAttribute('slot', 'actions');
|
|
86
|
+
menu.classList.add('has-actions');
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
119
89
|
}
|
|
120
90
|
|
|
121
|
-
// Click event
|
|
122
|
-
button.addEventListener(
|
|
123
|
-
'click',
|
|
124
|
-
function (e) {
|
|
125
|
-
e.preventDefault();
|
|
126
|
-
button.toggleAttribute('aria-expanded');
|
|
127
|
-
element.classList.toggle('open');
|
|
128
|
-
mdButton.classList.toggle('active');
|
|
129
91
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
iamNav.classList.remove('open');
|
|
147
|
-
backdrop.classList.remove('show');
|
|
148
|
-
setTimeout(function () {
|
|
149
|
-
element.classList.add('closed');
|
|
150
|
-
}, 1000);
|
|
151
|
-
}
|
|
92
|
+
// Create menu button
|
|
93
|
+
if (
|
|
94
|
+
element.classList.contains('nav--menu') &&
|
|
95
|
+
element.hasAttribute('data-title') &&
|
|
96
|
+
element.hasAttribute('data-icon')
|
|
97
|
+
) {
|
|
98
|
+
const title = element.getAttribute('data-title');
|
|
99
|
+
const iconClass = element.getAttribute('data-icon');
|
|
100
|
+
|
|
101
|
+
// Create the menu button that sits seperately to the menu
|
|
102
|
+
const button = document.createElement('button');
|
|
103
|
+
button.setAttribute('slot', title);
|
|
104
|
+
button.classList.add('btn-menu');
|
|
105
|
+
button.setAttribute('part', 'btn-menu');
|
|
106
|
+
button.innerHTML = `<span class="btn btn-primary"><span>${title}</span><i class="${iconClass}"></i><i class="fa-regular fa-xmark-large"></i></span>`;
|
|
107
|
+
buttonsHolder.insertAdjacentElement('beforeend', button);
|
|
152
108
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
109
|
+
const mdButton = button.querySelector('.btn-primary');
|
|
110
|
+
|
|
111
|
+
// Make sure the menu is added to the right part of the component
|
|
112
|
+
element.setAttribute('slot', 'menus');
|
|
113
|
+
|
|
114
|
+
// If open we need to make sure the main mobile menu is closed, the new button has the right state and the backdrop is shown
|
|
115
|
+
if (element.classList.contains('open')) {
|
|
116
|
+
button.setAttribute('aria-expanded', true);
|
|
117
|
+
mdButton.classList.toggle('active');
|
|
118
|
+
component.classList.add('open');
|
|
119
|
+
backdrop.classList.add('show');
|
|
120
|
+
} else {
|
|
121
|
+
element.classList.add('closed'); // closed class is added to prevent the elements being tabbed into, this causes visual issues
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Click event
|
|
125
|
+
button.addEventListener(
|
|
126
|
+
'click',
|
|
127
|
+
function (e) {
|
|
128
|
+
e.preventDefault();
|
|
129
|
+
button.toggleAttribute('aria-expanded');
|
|
130
|
+
|
|
131
|
+
console.log(element);
|
|
132
|
+
element.classList.toggle('open');
|
|
133
|
+
mdButton.classList.toggle('active');
|
|
134
|
+
|
|
135
|
+
// Close desktop menus
|
|
136
|
+
const openMenu = component.querySelector(':scope > details[open]');
|
|
137
|
+
|
|
138
|
+
if (openMenu) openMenu.removeAttribute('open');
|
|
139
|
+
|
|
140
|
+
// Close the main menu and fix states on the button, iamNav component and backdrop
|
|
141
|
+
if (element.classList.contains('open')) {
|
|
142
|
+
menu.classList.remove('open');
|
|
143
|
+
menuButton.removeAttribute('aria-expanded');
|
|
144
|
+
setTimeout(function () {
|
|
145
|
+
menu.classList.add('closed');
|
|
146
|
+
}, 1000); // Delay until its close so the animation is broken
|
|
147
|
+
component.classList.add('open');
|
|
148
|
+
backdrop.classList.add('show');
|
|
149
|
+
element.classList.remove('closed');
|
|
150
|
+
} else {
|
|
151
|
+
component.classList.remove('open');
|
|
152
|
+
backdrop.classList.remove('show');
|
|
153
|
+
setTimeout(function () {
|
|
154
|
+
element.classList.add('closed');
|
|
155
|
+
}, 1000);
|
|
157
156
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (selectedButton != button) {
|
|
164
|
-
selectedButton.removeAttribute('aria-expanded');
|
|
165
|
-
const innerBtn = selectedButton.querySelector('.btn-primary');
|
|
166
|
-
innerBtn.classList.remove('active');
|
|
157
|
+
|
|
158
|
+
// Close any open menus
|
|
159
|
+
component.querySelectorAll('.nav--menu.open').forEach(function (openmenu) {
|
|
160
|
+
if (openmenu != element) {
|
|
161
|
+
openmenu.classList.remove('open');
|
|
167
162
|
}
|
|
168
163
|
});
|
|
169
|
-
},
|
|
170
|
-
false
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
164
|
|
|
175
|
-
|
|
176
|
-
|
|
165
|
+
component.shadowRoot
|
|
166
|
+
.querySelectorAll('.buttons-holder .btn-menu[aria-expanded]')
|
|
167
|
+
.forEach(function (selectedButton) {
|
|
168
|
+
if (selectedButton != button) {
|
|
169
|
+
selectedButton.removeAttribute('aria-expanded');
|
|
170
|
+
const innerBtn = selectedButton.querySelector('.btn-primary');
|
|
171
|
+
innerBtn.classList.remove('active');
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
false
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
component.querySelectorAll('details').forEach(function (element) {
|
|
181
|
+
element.classList.add('details--revert');
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
createNavMenu(this);
|
|
185
|
+
|
|
186
|
+
this.addEventListener('rebuilt', () => {
|
|
187
|
+
console.log('rebuilt nav');
|
|
188
|
+
createNavMenu(this);
|
|
177
189
|
});
|
|
178
190
|
|
|
179
191
|
// Has secondary link
|
|
@@ -186,7 +198,7 @@ class iamNav extends HTMLElement {
|
|
|
186
198
|
'click',
|
|
187
199
|
function (e) {
|
|
188
200
|
e.preventDefault();
|
|
189
|
-
menuButton.toggleAttribute('aria-expanded');
|
|
201
|
+
//menuButton.toggleAttribute('aria-expanded');
|
|
190
202
|
menu.classList.toggle('open');
|
|
191
203
|
|
|
192
204
|
// Close any other menus
|
|
@@ -37,7 +37,7 @@ class iamSearch extends HTMLElement {
|
|
|
37
37
|
<slot></slot>
|
|
38
38
|
<button class="clear-search btn btn-action" type="button"><i class="fa-light fa-times me-0"></i></button>
|
|
39
39
|
</span>
|
|
40
|
-
<button class="suffix
|
|
40
|
+
<button class="suffix fa-regular fa-search"></button>
|
|
41
41
|
</span>
|
|
42
42
|
<slot name="datalist"></slot>
|
|
43
43
|
`;
|
|
@@ -56,6 +56,10 @@ class iamSearch extends HTMLElement {
|
|
|
56
56
|
|
|
57
57
|
let minLength = this.hasAttribute('data-min-length') ? getIntegerAttribute(this, 'data-min-length', 1) : 1;
|
|
58
58
|
|
|
59
|
+
|
|
60
|
+
suffixElement?.setAttribute('class',`suffix ${this.hasAttribute('data-icon') ? this.getAttribute('data-icon') : 'fa-regular fa-search'}`);
|
|
61
|
+
|
|
62
|
+
|
|
59
63
|
if (this.hasAttribute('data-url') && !this.hasAttribute('data-min-length')) {
|
|
60
64
|
|
|
61
65
|
minLength = 3;
|
|
@@ -36,6 +36,9 @@ class iamSTDNav extends HTMLElement {
|
|
|
36
36
|
const defaultContent = navElement.innerHTML;
|
|
37
37
|
|
|
38
38
|
navElement.innerHTML = `${defaultContent}${populateNav(data)}`;
|
|
39
|
+
|
|
40
|
+
const customEvent = new CustomEvent('rebuilt');
|
|
41
|
+
navElement.dispatchEvent(customEvent);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
defaultToSecondary = (): void => {
|
|
@@ -82,7 +85,6 @@ class iamSTDNav extends HTMLElement {
|
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
|
|
85
|
-
|
|
86
88
|
const data = await loadNavData(Cookies).then(
|
|
87
89
|
(data) => {
|
|
88
90
|
|
|
@@ -38,7 +38,7 @@ export const setupCard = (cardComponent: HTMLElement): void => {
|
|
|
38
38
|
const cardTotal = cardBody?.querySelector<HTMLDivElement>('.card__total');
|
|
39
39
|
|
|
40
40
|
if(!cardTotal)
|
|
41
|
-
cardBody
|
|
41
|
+
cardBody.insertAdjacentHTML(
|
|
42
42
|
'beforeend',
|
|
43
43
|
`<div class="card__total">${cardComponent.getAttribute('data-total') || ''}</div>`
|
|
44
44
|
);
|
|
@@ -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
|
+
});
|