@iamproperty/components 3.7.9-beta-2 → 3.8.0
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/accordion.css.map +1 -1
- package/assets/css/components/dialog.css +1 -1
- package/assets/css/components/dialog.css.map +1 -1
- package/assets/css/components/fileupload.css.map +1 -1
- package/assets/css/components/forms.css +1 -1
- package/assets/css/components/forms.css.map +1 -1
- package/assets/css/components/header.css +1 -1
- package/assets/css/components/header.css.map +1 -1
- package/assets/css/components/lists.css.map +1 -1
- package/assets/css/components/nav.css +1 -1
- package/assets/css/components/nav.css.map +1 -1
- package/assets/css/components/property-searchbar.css +1 -1
- package/assets/css/components/property-searchbar.css.map +1 -1
- package/assets/css/core.min.css +1 -1
- package/assets/css/core.min.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/applied-filters/applied-filters.component.min.js +1 -1
- package/assets/js/components/card/card.component.min.js +1 -1
- package/assets/js/components/filterlist/filterlist.component.min.js +1 -1
- package/assets/js/components/header/header.component.min.js +2 -2
- package/assets/js/components/notification/notification.component.min.js +1 -1
- package/assets/js/components/pagination/pagination.component.min.js +1 -1
- package/assets/js/components/table/table.component.min.js +12 -12
- package/assets/js/components/table/table.component.min.js.map +1 -1
- package/assets/js/components/tabs/tabs.component.min.js +1 -1
- package/assets/js/dynamic.min.js +5 -5
- package/assets/js/dynamic.min.js.map +1 -1
- package/assets/js/modules/dialogs.js +109 -24
- package/assets/js/modules/table.js +23 -5
- package/assets/js/scripts.bundle.js +22 -22
- package/assets/js/scripts.bundle.js.map +1 -1
- package/assets/js/scripts.bundle.min.js +2 -2
- package/assets/js/scripts.bundle.min.js.map +1 -1
- package/assets/js/tests/filterlist.spec.js +1 -1
- package/assets/sass/_functions/variables.scss +4 -2
- package/assets/sass/components/dialog.scss +156 -5
- package/assets/sass/components/forms.scss +67 -21
- package/assets/sass/foundations/buttons.scss +48 -0
- package/assets/ts/modules/dialogs.ts +156 -29
- package/assets/ts/modules/table.ts +29 -7
- package/assets/ts/tests/dialogs.spec.js +50 -0
- package/assets/ts/tests/filterlist.spec.ts +1 -1
- package/dist/components.es.js +838 -830
- package/dist/components.umd.js +28 -28
- package/dist/style.css +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,20 @@ import { createEmbed } from "./youtubevideo";
|
|
|
3
3
|
|
|
4
4
|
const extendDialogs = (body) => {
|
|
5
5
|
|
|
6
|
+
Array.from(body.querySelectorAll('dialog[open]')).forEach((dialog, index) => {
|
|
7
|
+
|
|
8
|
+
let parent = dialog.closest('.dialog__wrapper');
|
|
9
|
+
|
|
10
|
+
if(!parent){
|
|
11
|
+
|
|
12
|
+
dialog.removeAttribute('open');
|
|
13
|
+
dialog.showModal();
|
|
14
|
+
dialog.focus();
|
|
15
|
+
|
|
16
|
+
createDialog(dialog);
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
6
20
|
// Dialogs/modals
|
|
7
21
|
body.addEventListener('click', (event) => {
|
|
8
22
|
|
|
@@ -15,20 +29,6 @@ const extendDialogs = (body) => {
|
|
|
15
29
|
|
|
16
30
|
createDialog(dialog);
|
|
17
31
|
|
|
18
|
-
|
|
19
|
-
// Prevent the user from escaping the model when transactional
|
|
20
|
-
if(dialog.querySelector(':scope > .mh-lg > form:last-child > button:last-child, :scope > .mh-lg > button:last-child') && !dialog.classList.contains('dialog--multi')) {
|
|
21
|
-
dialog.addEventListener("cancel", (e) => {
|
|
22
|
-
e.preventDefault();
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Create the video embed
|
|
27
|
-
let videoButton = dialog.querySelector('.youtube-embed a');
|
|
28
|
-
if (videoButton){
|
|
29
|
-
createEmbed(videoButton)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
32
|
// Open the modal!
|
|
33
33
|
dialog.showModal();
|
|
34
34
|
dialog.focus();
|
|
@@ -77,7 +77,12 @@ const extendDialogs = (body) => {
|
|
|
77
77
|
|
|
78
78
|
// Close the modal when clicked on the backdrop
|
|
79
79
|
if (event && event.target instanceof HTMLElement && event.target.closest('dialog[open]')){
|
|
80
|
-
|
|
80
|
+
let dialog = event.target.closest('dialog[open]');
|
|
81
|
+
|
|
82
|
+
// Small fix to make sure the dialog isn't a dialog inside of a dialog.
|
|
83
|
+
var style = window.getComputedStyle(dialog);
|
|
84
|
+
if(style.display === 'contents')
|
|
85
|
+
dialog = dialog.parentNode.closest('dialog[open]');
|
|
81
86
|
|
|
82
87
|
// Dont allow the backdrop to be clicked when transactional
|
|
83
88
|
if(!dialog.querySelector(':scope > .mh-lg > form:last-child > button:last-child, :scope > .mh-lg > button:last-child') || dialog.classList.contains('dialog--multi')){
|
|
@@ -106,8 +111,8 @@ const extendDialogs = (body) => {
|
|
|
106
111
|
let dataEvent = "openPopover"
|
|
107
112
|
let popover = parent.querySelector(':scope > dialog');
|
|
108
113
|
|
|
109
|
-
if(document.querySelector('dialog[open]') && document.querySelector('dialog[open]') != popover)
|
|
110
|
-
document.querySelector('dialog[open]').close();
|
|
114
|
+
if(document.querySelector('*:not([data-keep-open]) > dialog[open]') && document.querySelector('*:not([data-keep-open]) > dialog[open]') != popover)
|
|
115
|
+
document.querySelector('*:not([data-keep-open]) > dialog[open]').close();
|
|
111
116
|
|
|
112
117
|
// Remove active class from exiting active buttons
|
|
113
118
|
Array.from(document.querySelectorAll('.dialog__wrapper > button')).forEach((btnElement,index) => {
|
|
@@ -152,8 +157,14 @@ const extendDialogs = (body) => {
|
|
|
152
157
|
if(popoverBottom > windowPos){
|
|
153
158
|
|
|
154
159
|
let currentStyle = popover.hasAttribute('style') ? popover.getAttribute('style')+' ' : '';
|
|
155
|
-
|
|
156
160
|
popover.setAttribute('style',currentStyle+`transform: translate(0, calc(-100% - 4rem))`);
|
|
161
|
+
|
|
162
|
+
// Check that the dialog doesn't go over the top of the page
|
|
163
|
+
boundingRec = popover.getBoundingClientRect();
|
|
164
|
+
let popoverTop = boundingRec.top - window.scrollY;
|
|
165
|
+
|
|
166
|
+
if(popoverTop < 100)
|
|
167
|
+
popover.removeAttribute('style');
|
|
157
168
|
}
|
|
158
169
|
|
|
159
170
|
window.dataLayer = window.dataLayer || [];
|
|
@@ -181,11 +192,25 @@ const extendDialogs = (body) => {
|
|
|
181
192
|
|
|
182
193
|
export const createDialog = (dialog) => {
|
|
183
194
|
|
|
195
|
+
// Prevent the user from escaping the model when transactional
|
|
196
|
+
if(dialog.querySelector(':scope > .mh-lg > form:last-child > button:last-child, :scope > .mh-lg > button:last-child') && !dialog.classList.contains('dialog--multi')) {
|
|
197
|
+
dialog.addEventListener("cancel", (e) => {
|
|
198
|
+
e.preventDefault();
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Create the video embed
|
|
203
|
+
let videoButton = dialog.querySelector('.youtube-embed a');
|
|
204
|
+
if (videoButton){
|
|
205
|
+
createEmbed(videoButton)
|
|
206
|
+
}
|
|
207
|
+
|
|
184
208
|
// Multi dialog
|
|
185
209
|
if(dialog.classList.contains('dialog--multi') && !dialog.querySelector(':scope > .steps')) {
|
|
186
210
|
createMultiFormDialog(dialog);
|
|
187
211
|
}
|
|
188
212
|
|
|
213
|
+
// If you are using Vue eevents and bindings its recommended to add in the .mh-lg div manually to the dialog
|
|
189
214
|
if(!dialog.querySelector(':scope > .mh-lg') && !dialog.classList.contains('dialog--multi')){
|
|
190
215
|
dialog.innerHTML = `<div class="mh-lg">${dialog.innerHTML}</div>`;
|
|
191
216
|
|
|
@@ -205,37 +230,101 @@ export const createDialog = (dialog) => {
|
|
|
205
230
|
|
|
206
231
|
// Create close button is needed
|
|
207
232
|
if(!dialog.querySelector(':scope > button:first-child'))
|
|
208
|
-
dialog.
|
|
233
|
+
dialog.insertAdjacentHTML('afterbegin', `<button class="dialog__close">Close</button>`);
|
|
209
234
|
|
|
210
235
|
}
|
|
211
236
|
|
|
212
|
-
const createMultiFormDialog = (dialog) => {
|
|
237
|
+
export const createMultiFormDialog = (dialog) => {
|
|
238
|
+
|
|
213
239
|
let buttons = "";
|
|
214
240
|
let fieldsets = Array.from(dialog.querySelectorAll('fieldset[data-title]'));
|
|
241
|
+
|
|
215
242
|
fieldsets.forEach((fieldset,index) => {
|
|
216
|
-
buttons += `<button data-title="${fieldset.getAttribute('data-title')}" type="button" class="${index == 0 ? "active":""}">${fieldset.getAttribute('data-title')}</button>`;
|
|
243
|
+
buttons += `<button data-title="${fieldset.getAttribute('data-title')}" type="button" class="${index == 0 ? "active":""}" tabindex="-1">${fieldset.getAttribute('data-title')}</button>`;
|
|
217
244
|
|
|
218
245
|
const btnWrapper = document.createElement("div");
|
|
219
246
|
btnWrapper.classList.add('btn--wrapper');
|
|
220
247
|
fieldset.appendChild(btnWrapper);
|
|
221
248
|
|
|
222
|
-
|
|
223
249
|
if(index != 0)
|
|
224
|
-
btnWrapper.innerHTML += `<button data-title="${fieldsets[index-1].getAttribute('data-title')}" class="btn btn-secondary mb-0" type="button">Previous</button>`;
|
|
250
|
+
btnWrapper.innerHTML += `<button data-title="${fieldsets[index-1].getAttribute('data-title')}" class="btn btn-secondary mb-0" data-previous type="button">Previous</button>`;
|
|
225
251
|
|
|
226
252
|
if(index != fieldsets.length - 1)
|
|
227
|
-
btnWrapper.innerHTML += `<button data-title="${fieldsets[index+1].getAttribute('data-title')}" class="btn btn-primary mb-0" type="button">Next</button>`;
|
|
253
|
+
btnWrapper.innerHTML += `<button data-title="${fieldsets[index+1].getAttribute('data-title')}" class="btn btn-primary mb-0" data-next type="button">Next</button>`;
|
|
228
254
|
|
|
229
255
|
if(index == fieldsets.length - 1)
|
|
230
|
-
btnWrapper.innerHTML += `<button class="btn btn-primary mb-0">Submit</button>`;
|
|
256
|
+
btnWrapper.innerHTML += `<button data-title="${fieldsets[index].getAttribute('data-title')}" class="btn btn-primary mb-0" data-next type="submit">Submit</button>`;
|
|
231
257
|
});
|
|
232
258
|
|
|
233
|
-
dialog.
|
|
259
|
+
dialog.insertAdjacentHTML('afterbegin',`<div class="steps bg-primary">${buttons}</div>`);
|
|
234
260
|
|
|
235
261
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
262
|
+
// Open the fieldset with an error inside
|
|
263
|
+
let validatedFieldsets = Array.from(dialog.querySelectorAll('fieldset.was-validated'));
|
|
264
|
+
for (let i = 0; i < validatedFieldsets.length; i++) {
|
|
265
|
+
|
|
266
|
+
let fieldset = validatedFieldsets[i];
|
|
267
|
+
let fieldsetID = fieldset.getAttribute('data-title');
|
|
268
|
+
|
|
269
|
+
if(fieldset.querySelector('.is-invalid')){
|
|
270
|
+
|
|
271
|
+
Array.from(dialog.querySelectorAll(`[data-title="${fieldsetID}"]`)).forEach((element, index) => {
|
|
272
|
+
|
|
273
|
+
element.classList.add('active');
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
break;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
|
|
280
|
+
Array.from(dialog.querySelectorAll(`[data-title="${fieldsetID}"]`)).forEach((element, index) => {
|
|
281
|
+
|
|
282
|
+
element.classList.add('valid');
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Prevent the bubble messages
|
|
288
|
+
dialog.addEventListener('invalid', (function () {
|
|
289
|
+
return function (e) {
|
|
290
|
+
e.preventDefault();
|
|
291
|
+
};
|
|
292
|
+
})(), true);
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
function validateFieldset(button){
|
|
296
|
+
|
|
297
|
+
const currentFieldset = dialog.querySelector(`fieldset.active`) ? dialog.querySelector(`fieldset.active`) : dialog.querySelector(`fieldset[data-title]`);
|
|
298
|
+
const currentFieldsetID = currentFieldset.getAttribute('data-title');
|
|
299
|
+
let isFieldsetValid = true;
|
|
300
|
+
|
|
301
|
+
currentFieldset.classList.add('was-validated');
|
|
302
|
+
|
|
303
|
+
Array.from(currentFieldset.querySelectorAll('input')).forEach((input, index) => {
|
|
304
|
+
|
|
305
|
+
if (!input.checkValidity())
|
|
306
|
+
isFieldsetValid = false;
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// If valid mode to next field set
|
|
310
|
+
if(!isFieldsetValid){
|
|
311
|
+
|
|
312
|
+
Array.from(dialog.querySelectorAll(`[data-title="${currentFieldsetID}"]`)).forEach((element, index) => {
|
|
313
|
+
|
|
314
|
+
element.classList.remove('valid');
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
|
|
319
|
+
Array.from(dialog.querySelectorAll(`[data-title="${currentFieldsetID}"]`)).forEach((element, index) => {
|
|
320
|
+
|
|
321
|
+
element.classList.add('valid');
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Allow the previous button to navigate
|
|
326
|
+
if(isFieldsetValid || !button.hasAttribute('data-next')){
|
|
327
|
+
|
|
239
328
|
const fieldset = dialog.querySelector(`fieldset[data-title="${button.getAttribute('data-title')}"]`);
|
|
240
329
|
const step = dialog.querySelector(`.steps button[data-title="${button.getAttribute('data-title')}"]`);
|
|
241
330
|
|
|
@@ -248,6 +337,44 @@ const createMultiFormDialog = (dialog) => {
|
|
|
248
337
|
|
|
249
338
|
step.classList.add('active');
|
|
250
339
|
fieldset.classList.add('active');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
let fieldsetCount = Array.from(dialog.querySelectorAll(`fieldset`)).length;
|
|
344
|
+
let validFieldsetCount = Array.from(dialog.querySelectorAll(`fieldset.valid`)).length;
|
|
345
|
+
|
|
346
|
+
// update the progress bar
|
|
347
|
+
dialog.style.setProperty('--progress', `${(validFieldsetCount/(fieldsetCount - 1) * 100)}%`);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// remove error messages from server
|
|
351
|
+
dialog.addEventListener('keydown', (event) => {
|
|
352
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('button')){
|
|
353
|
+
|
|
354
|
+
const button = event.target.closest('button');
|
|
355
|
+
|
|
356
|
+
if(event.keyCode == 13){
|
|
357
|
+
|
|
358
|
+
event.preventDefault();
|
|
359
|
+
validateFieldset(button);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('input')){
|
|
364
|
+
const input = event.target.closest('input');
|
|
365
|
+
|
|
366
|
+
input.classList.remove('is-invalid');
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
dialog.addEventListener('click', (event) => {
|
|
374
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('button[data-title]')){
|
|
375
|
+
|
|
376
|
+
const button = event.target.closest('button[data-title]');
|
|
377
|
+
validateFieldset(button);
|
|
251
378
|
};
|
|
252
379
|
return null
|
|
253
380
|
});
|
|
@@ -453,15 +453,26 @@ export const filterTable = (table, form, wrapper) => {
|
|
|
453
453
|
});
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
-
//Display the filter count
|
|
456
|
+
// Display the filter count
|
|
457
457
|
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
458
458
|
element.innerHTML = '';
|
|
459
|
+
element.parentNode.classList.remove('hover');
|
|
459
460
|
});
|
|
460
461
|
|
|
461
|
-
|
|
462
|
-
|
|
462
|
+
let filterCount = 0;
|
|
463
|
+
Object.values(filters).forEach((filter, index) => {
|
|
464
|
+
|
|
465
|
+
if(typeof filter == "object" && Object.values(filter).length)
|
|
466
|
+
filterCount += Object.values(filter).length;
|
|
467
|
+
else
|
|
468
|
+
filterCount++;
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
if(filterCount) {
|
|
472
|
+
|
|
463
473
|
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
464
|
-
element.innerHTML += `(${
|
|
474
|
+
element.innerHTML += `(${filterCount})`;
|
|
475
|
+
element.parentNode.classList.add('hover');
|
|
465
476
|
});
|
|
466
477
|
}
|
|
467
478
|
|
|
@@ -829,12 +840,23 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
|
|
|
829
840
|
|
|
830
841
|
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
831
842
|
element.innerHTML = '';
|
|
843
|
+
element.parentNode.classList.remove('hover');
|
|
832
844
|
});
|
|
833
845
|
|
|
834
|
-
|
|
835
|
-
|
|
846
|
+
let filterCount = 0;
|
|
847
|
+
Object.values(filters).forEach((filter, index) => {
|
|
848
|
+
|
|
849
|
+
if(typeof filter == "object" && Object.values(filter).length)
|
|
850
|
+
filterCount += Object.values(filter).length;
|
|
851
|
+
else
|
|
852
|
+
filterCount++;
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
if(filterCount) {
|
|
856
|
+
|
|
836
857
|
Array.from(form.querySelectorAll('[data-filter-count]')).forEach((element, index) => {
|
|
837
|
-
element.innerHTML += `(${
|
|
858
|
+
element.innerHTML += `(${filterCount})`;
|
|
859
|
+
element.parentNode.classList.add('hover');
|
|
838
860
|
});
|
|
839
861
|
}
|
|
840
862
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
import '@testing-library/jest-dom'
|
|
3
|
+
import { createMultiFormDialog } from "../modules/dialogs";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
describe('createMultiFormDialog', () => {
|
|
7
|
+
let dialog;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Create a fresh dialog element before each test
|
|
11
|
+
dialog = document.createElement('dialog');
|
|
12
|
+
dialog.innerHTML = `
|
|
13
|
+
<fieldset data-title="fieldset1">
|
|
14
|
+
<input type="text" >
|
|
15
|
+
</fieldset>
|
|
16
|
+
<fieldset data-title="fieldset2">
|
|
17
|
+
<input type="text" >
|
|
18
|
+
</fieldset>
|
|
19
|
+
`;
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('it initializes buttons and fieldsets', () => {
|
|
23
|
+
createMultiFormDialog(dialog);
|
|
24
|
+
|
|
25
|
+
expect(dialog.querySelectorAll('.steps').length).toEqual(1);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('it validates fieldsets and updates classes', () => {
|
|
29
|
+
createMultiFormDialog(dialog);
|
|
30
|
+
|
|
31
|
+
// Simulate a button click to trigger validation
|
|
32
|
+
const button = dialog.querySelector('button[data-title="fieldset1"]');
|
|
33
|
+
button.click();
|
|
34
|
+
|
|
35
|
+
// Add your assertions here to check if validation and class updates are working as expected
|
|
36
|
+
expect(dialog.querySelectorAll('fieldset[data-title="fieldset1"].active').length).toEqual(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('it navigates to the next fieldset', () => {
|
|
40
|
+
createMultiFormDialog(dialog);
|
|
41
|
+
|
|
42
|
+
// Simulate a button click to navigate to the next fieldset
|
|
43
|
+
const button = dialog.querySelector('button[data-title="fieldset2"]');
|
|
44
|
+
button.click();
|
|
45
|
+
|
|
46
|
+
// Add your assertions here to check if navigation to the next fieldset is working
|
|
47
|
+
expect(dialog.querySelectorAll('fieldset[data-title="fieldset2"].active').length).toEqual(1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
});
|