@iamproperty/components 3.7.9 → 3.9.0-beta-1
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/actionbar-global.css +1 -0
- package/assets/css/components/actionbar-global.css.map +1 -0
- package/assets/css/components/actionbar.css +1 -0
- package/assets/css/components/actionbar.css.map +1 -0
- 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-global.css +1 -0
- package/assets/css/components/nav-global.css.map +1 -0
- package/assets/css/components/nav.css +1 -1
- package/assets/css/components/nav.css.map +1 -1
- package/assets/css/components/nav.docs.css +1 -0
- package/assets/css/components/nav.docs.css.map +1 -0
- package/assets/css/components/nav.old.css +1 -0
- package/assets/css/components/nav.old.css.map +1 -0
- package/assets/css/components/pagination.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/components/table.css +1 -1
- package/assets/css/components/table.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/actionbar/actionbar.component.js +305 -0
- package/assets/js/components/actionbar/actionbar.component.min.js +53 -0
- package/assets/js/components/actionbar/actionbar.component.min.js.map +1 -0
- 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/nav/nav.component.js +294 -0
- package/assets/js/components/nav/nav.component.min.js +51 -0
- package/assets/js/components/nav/nav.component.min.js.map +1 -0
- 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.js +33 -0
- package/assets/js/components/table/table.component.min.js +11 -10
- 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 +3 -3
- package/assets/js/dynamic.min.js.map +1 -1
- package/assets/js/modules/dialogs.js +18 -5
- package/assets/js/modules/table.js +22 -4
- package/assets/js/scripts.bundle.js +15 -14
- 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/sass/_corefiles.scss +2 -0
- package/assets/sass/_functions/mixins.scss +25 -0
- package/assets/sass/_functions/variables.scss +5 -3
- package/assets/sass/components/actionbar-global.scss +89 -0
- package/assets/sass/components/actionbar.scss +254 -0
- package/assets/sass/components/dialog.scss +99 -1
- package/assets/sass/components/forms.scss +96 -21
- package/assets/sass/components/nav-global.scss +619 -0
- package/assets/sass/components/nav.docs.scss +54 -0
- package/assets/sass/components/nav.old.scss +965 -0
- package/assets/sass/components/nav.scss +450 -782
- package/assets/sass/components/table.scss +9 -1
- package/assets/sass/foundations/buttons.scss +87 -14
- package/assets/sass/foundations/links.scss +1 -1
- package/assets/sass/foundations/reboot.scss +5 -3
- package/assets/ts/components/actionbar/README.md +55 -0
- package/assets/ts/components/actionbar/actionbar.component.ts +396 -0
- package/assets/ts/components/nav/README.md +68 -0
- package/assets/ts/components/nav/nav.component.ts +370 -0
- package/assets/ts/components/table/table.component.ts +65 -0
- package/assets/ts/modules/dialogs.ts +24 -6
- package/assets/ts/modules/table.ts +29 -7
- package/dist/components.es.js +1013 -1258
- package/dist/components.umd.js +97 -47
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/Actionbar/Actionbar.vue +20 -0
- package/src/components/Actionbar/README.md +40 -0
- package/src/components/Nav/Nav.vue +20 -195
- package/src/components/Nav/README.md +43 -13
- package/src/components/Nav-old/Nav.vue +213 -0
- package/src/components/Nav-old/README.md +23 -0
- package/src/components/Nav/Nav.spec.js +0 -35
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
**Add the below to your initialise script**
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
import('../node_modules/@iamproperty/components/assets/js/components/nav/nav.component.min').then(module => { // Might need to update the path
|
|
5
|
+
|
|
6
|
+
if (!window.customElements.get(`iam-nav`))
|
|
7
|
+
window.customElements.define(`iam-nav`, 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
|
+
<nav>
|
|
18
|
+
<iam-nav>
|
|
19
|
+
<a href="/" class="brand brand--property" slot="logo">
|
|
20
|
+
<svg>
|
|
21
|
+
<title>iamproperty</title>
|
|
22
|
+
<use xlink:href="/svg/logo.svg#logo-property"></use>
|
|
23
|
+
</svg>
|
|
24
|
+
</a>
|
|
25
|
+
|
|
26
|
+
<a href="/" class="selected">Lorem ipsum</a>
|
|
27
|
+
<a href="/">Lorem ipsum</a>
|
|
28
|
+
<a href="/">Lorem ipsum</a>
|
|
29
|
+
<a href="/">Lorem ipsum</a>
|
|
30
|
+
|
|
31
|
+
<button class="btn btn-primary">Lorem ipsum</button>
|
|
32
|
+
</iam-nav>
|
|
33
|
+
</nav>
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Properties**
|
|
37
|
+
|
|
38
|
+
| Option | Type | Default Value | Description |
|
|
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
|
+
| data-searcd-open | String | - | Flag that opens the search bar on desktop on page load. |
|
|
44
|
+
|
|
45
|
+
**Slots**
|
|
46
|
+
|
|
47
|
+
| Option | Default Value | Description |
|
|
48
|
+
| ------ | ------------- | ----------- |
|
|
49
|
+
| default | - | Populates the main nav area |
|
|
50
|
+
| logo | - | A place to add the logo to the site |
|
|
51
|
+
| secondary | - | Moves the link upto the top of the navbar on desktop |
|
|
52
|
+
| actions | - | A place to add buttons |
|
|
53
|
+
| dual | - | Plave the link or list to the right of the nav, forcing the default slot to the left. |
|
|
54
|
+
|
|
55
|
+
**Class modifiers**
|
|
56
|
+
|
|
57
|
+
- Adding a class of **.bg-primary** will change the background of the navbar without chaning the menu background.
|
|
58
|
+
- 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 } |
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
|
|
3
|
+
// Data layer Web component created
|
|
4
|
+
window.dataLayer = window.dataLayer || [];
|
|
5
|
+
window.dataLayer.push({
|
|
6
|
+
"event": "customElementRegistered",
|
|
7
|
+
"element": "nav"
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
class iamNav extends HTMLElement {
|
|
11
|
+
|
|
12
|
+
constructor(){
|
|
13
|
+
super();
|
|
14
|
+
const shadowRoot = 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/nav.css";`;
|
|
19
|
+
|
|
20
|
+
const template = document.createElement('template');
|
|
21
|
+
template.innerHTML = `
|
|
22
|
+
<style class="styles">
|
|
23
|
+
@import "${coreCSS}";
|
|
24
|
+
${loadCSS}
|
|
25
|
+
</style>
|
|
26
|
+
<link rel="stylesheet" href="https://kit.fontawesome.com/26fdbf0179.css" crossorigin="anonymous">
|
|
27
|
+
<div class="container">
|
|
28
|
+
<slot name="logo"></slot>
|
|
29
|
+
<div class="buttons-holder"></div>
|
|
30
|
+
<button class="btn-menu">Menu<i class="fa-regular fa-bars"></i><i class="fa-regular fa-xmark-large"></i></button>
|
|
31
|
+
|
|
32
|
+
<div class="menu__outer">
|
|
33
|
+
<div class="menu closed">
|
|
34
|
+
|
|
35
|
+
<div class="menu__primary">
|
|
36
|
+
<slot></slot>
|
|
37
|
+
<slot name="dual"></slot>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="dialog__wrapper d-none" id="search-wrapper"></div>
|
|
40
|
+
<slot name="actions"></slot>
|
|
41
|
+
<div class="menu__secondary">
|
|
42
|
+
<div class="container">
|
|
43
|
+
<slot name="secondary"></slot>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
<slot name="menus"></slot>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="lists"></div>
|
|
51
|
+
<div class="backdrop" part="backdrop"></div>
|
|
52
|
+
`;
|
|
53
|
+
|
|
54
|
+
shadowRoot.appendChild(template.content.cloneNode(true));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
connectedCallback() {
|
|
58
|
+
|
|
59
|
+
// Load external CSS if needed
|
|
60
|
+
if(this.hasAttribute('data-css'))
|
|
61
|
+
this.shadowRoot.querySelector('.styles').insertAdjacentHTML('beforeend', `@import "${this.getAttribute('data-css')}";`);
|
|
62
|
+
|
|
63
|
+
const menuButton = this.shadowRoot.querySelector('.btn-menu');
|
|
64
|
+
const menu = this.shadowRoot.querySelector('.menu');
|
|
65
|
+
const iamNav = this;
|
|
66
|
+
const backdrop = this.shadowRoot.querySelector('.backdrop');
|
|
67
|
+
const buttonsHolder = this.shadowRoot.querySelector('.buttons-holder');
|
|
68
|
+
|
|
69
|
+
// Check the content
|
|
70
|
+
this.querySelectorAll(':scope > *').forEach(function(element){
|
|
71
|
+
let tagname = element.tagName;
|
|
72
|
+
|
|
73
|
+
switch(tagname){
|
|
74
|
+
case "BUTTON":
|
|
75
|
+
element.setAttribute('slot','actions');
|
|
76
|
+
menu.classList.add('has-actions')
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Create menu button
|
|
81
|
+
if(element.classList.contains('nav--menu') && element.hasAttribute('data-title') && element.hasAttribute('data-icon')){
|
|
82
|
+
|
|
83
|
+
const title = element.getAttribute('data-title');
|
|
84
|
+
const iconClass = element.getAttribute('data-icon');
|
|
85
|
+
|
|
86
|
+
// Create the menu button that sits seperately to the menu
|
|
87
|
+
const button = document.createElement('button');
|
|
88
|
+
button.setAttribute('slot',title);
|
|
89
|
+
button.classList.add('btn-menu');
|
|
90
|
+
button.innerHTML = `<span class="btn btn-primary"><span>${title}</span><i class="${iconClass}"></i><i class="fa-regular fa-xmark-large"></i></span>`;
|
|
91
|
+
buttonsHolder.insertAdjacentElement('beforeend',button);
|
|
92
|
+
|
|
93
|
+
const mdButton = button.querySelector('.btn-primary');
|
|
94
|
+
|
|
95
|
+
// Make sure the menu is added to the right part of the component
|
|
96
|
+
element.setAttribute('slot','menus');
|
|
97
|
+
|
|
98
|
+
// 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
|
|
99
|
+
if(element.classList.contains('open')){
|
|
100
|
+
button.classList.add('selected');
|
|
101
|
+
mdButton.classList.toggle('active');
|
|
102
|
+
iamNav.classList.add('open');
|
|
103
|
+
backdrop.classList.add('show');
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
element.classList.add('closed'); // closed class is added to prevent the elements being tabbed into, this causes visual issues
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Click event
|
|
110
|
+
button.addEventListener('click', function(e){
|
|
111
|
+
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
button.classList.toggle('selected');
|
|
114
|
+
element.classList.toggle('open');
|
|
115
|
+
mdButton.classList.toggle('active');
|
|
116
|
+
|
|
117
|
+
// Close desktop menus
|
|
118
|
+
let openMenu = iamNav.querySelector(':scope > details[open]');
|
|
119
|
+
|
|
120
|
+
if(openMenu)
|
|
121
|
+
openMenu.removeAttribute('open')
|
|
122
|
+
|
|
123
|
+
// Close the main menu and fix states on the button, iamNav component and backdrop
|
|
124
|
+
if(element.classList.contains('open')){
|
|
125
|
+
|
|
126
|
+
menu.classList.remove('open');
|
|
127
|
+
menuButton.classList.remove('selected');
|
|
128
|
+
setTimeout(function(){ menu.classList.add('closed') }, 1000); // Delay until its close so the animation is broken
|
|
129
|
+
iamNav.classList.add('open');
|
|
130
|
+
backdrop.classList.add('show');
|
|
131
|
+
element.classList.remove('closed');
|
|
132
|
+
}
|
|
133
|
+
else{
|
|
134
|
+
iamNav.classList.remove('open');
|
|
135
|
+
backdrop.classList.remove('show');
|
|
136
|
+
setTimeout(function(){ element.classList.add('closed') }, 1000);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Close any open menus
|
|
140
|
+
iamNav.querySelectorAll('.nav--menu.open').forEach(function(openmenu){
|
|
141
|
+
if(openmenu != element) {
|
|
142
|
+
openmenu.classList.remove('open');
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
iamNav.shadowRoot.querySelectorAll('.buttons-holder .btn-menu.selected').forEach(function(selectedButton){
|
|
147
|
+
|
|
148
|
+
if(selectedButton != button){
|
|
149
|
+
|
|
150
|
+
selectedButton.classList.remove('selected');
|
|
151
|
+
let innerBtn = selectedButton.querySelector('.btn-primary');
|
|
152
|
+
innerBtn.classList.remove('active');
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
}, false);
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Has secondary link
|
|
161
|
+
if(this.querySelector('a[slot="secondary"]')){
|
|
162
|
+
menu.classList.add('has-secondary');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Create a scroll width variable to help with the sizing of the menu with in the CSS
|
|
166
|
+
document.documentElement.style.setProperty('--scrollbar-width', (window.innerWidth - document.documentElement.offsetWidth) + 'px');
|
|
167
|
+
|
|
168
|
+
// Open and close the menu
|
|
169
|
+
menuButton.addEventListener('click', function(e){
|
|
170
|
+
|
|
171
|
+
e.preventDefault();
|
|
172
|
+
menuButton.classList.toggle('selected');
|
|
173
|
+
menu.classList.toggle('open');
|
|
174
|
+
|
|
175
|
+
// Close any other menus
|
|
176
|
+
iamNav.querySelectorAll('.nav--menu.open').forEach(function(element){
|
|
177
|
+
element.classList.remove('open');
|
|
178
|
+
setTimeout(function(){ element.classList.add('closed') }, 1000);
|
|
179
|
+
});
|
|
180
|
+
iamNav.shadowRoot.querySelectorAll('.buttons-holder .btn-menu.selected').forEach(function(element){
|
|
181
|
+
element.classList.remove('selected');
|
|
182
|
+
let innerBtn = element.querySelector('.btn-primary');
|
|
183
|
+
innerBtn.classList.remove('active');
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
if(menu.classList.contains('open')){
|
|
187
|
+
iamNav.classList.add('open');
|
|
188
|
+
menu.classList.remove('closed');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
iamNav.classList.remove('open');
|
|
192
|
+
setTimeout(function(){ menu.classList.add('closed') }, 1000);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
}, false);
|
|
196
|
+
|
|
197
|
+
// Allow outside JS to close the menu
|
|
198
|
+
this.addEventListener("request-close", (event) => {
|
|
199
|
+
|
|
200
|
+
menuButton.classList.remove('selected');
|
|
201
|
+
menu.classList.remove('open');
|
|
202
|
+
iamNav.classList.remove('open');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Close the menu on the click of the backdrop on desktop
|
|
206
|
+
backdrop.addEventListener("click", (event) => {
|
|
207
|
+
|
|
208
|
+
let openMenu = this.querySelector('details[open] summary');
|
|
209
|
+
|
|
210
|
+
if(openMenu)
|
|
211
|
+
openMenu.click();
|
|
212
|
+
|
|
213
|
+
iamNav.querySelectorAll('.nav--menu.open').forEach(function(element){
|
|
214
|
+
element.classList.remove('open');
|
|
215
|
+
});
|
|
216
|
+
iamNav.shadowRoot.querySelectorAll('.buttons-holder .btn-menu.selected').forEach(function(element){
|
|
217
|
+
element.classList.remove('selected');
|
|
218
|
+
let innerBtn = element.querySelector('.btn-primary');
|
|
219
|
+
innerBtn.classList.remove('active');
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
backdrop.classList.remove('show');
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// On desktop close other menu's (details) when one is clicked
|
|
226
|
+
this.addEventListener("click", (event) => {
|
|
227
|
+
|
|
228
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('summary')){
|
|
229
|
+
|
|
230
|
+
if(window.innerWidth > 992){
|
|
231
|
+
|
|
232
|
+
let summary = event.target.closest('summary');
|
|
233
|
+
let details = summary.closest('details');
|
|
234
|
+
let wrapper = details.parentNode;
|
|
235
|
+
|
|
236
|
+
if(details.hasAttribute('open'))
|
|
237
|
+
details.removeAttribute('open');
|
|
238
|
+
else
|
|
239
|
+
details.setAttribute('open','true');
|
|
240
|
+
|
|
241
|
+
// Close any bespoke menus
|
|
242
|
+
iamNav.querySelectorAll('.nav--menu.open').forEach(function(element){
|
|
243
|
+
element.classList.remove('open');
|
|
244
|
+
setTimeout(function(){ menu.classList.add('closed') }, 1000);
|
|
245
|
+
});
|
|
246
|
+
iamNav.shadowRoot.querySelectorAll('.buttons-holder .btn-menu.selected').forEach(function(element){
|
|
247
|
+
element.classList.remove('selected');
|
|
248
|
+
let innerBtn = element.querySelector('.btn-primary');
|
|
249
|
+
innerBtn.classList.remove('active');
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
// Close any other dropdowns on the same level
|
|
253
|
+
Array.from(wrapper.querySelectorAll(':scope > details')).forEach((detailsArrayElement, index) => {
|
|
254
|
+
|
|
255
|
+
if(detailsArrayElement != details)
|
|
256
|
+
detailsArrayElement.removeAttribute('open')
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if(this.querySelectorAll(':scope > details[open]').length){
|
|
260
|
+
backdrop.classList.add('show');
|
|
261
|
+
iamNav.classList.add('open');
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
backdrop.classList.remove('show');
|
|
265
|
+
iamNav.classList.remove('open');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
event.preventDefault();
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Mega menu title
|
|
274
|
+
this.querySelectorAll('details').forEach((detailsElement) => {
|
|
275
|
+
|
|
276
|
+
let summary = detailsElement.querySelector('summary');
|
|
277
|
+
let containerDiv = detailsElement.querySelector(':Scope > div');
|
|
278
|
+
|
|
279
|
+
containerDiv.setAttribute('data-title', summary.textContent);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
// Search
|
|
283
|
+
if(this.hasAttribute('data-search')){
|
|
284
|
+
menu.classList.add('has-search');
|
|
285
|
+
let searchWrapper = this.shadowRoot.querySelector('#search-wrapper');
|
|
286
|
+
|
|
287
|
+
searchWrapper.classList.remove('d-none');
|
|
288
|
+
searchWrapper.insertAdjacentHTML('afterbegin',`<button class="btn btn-secondary btn-compact fa-search me-0 mb-0" id="search-button">Open Search field</button>
|
|
289
|
+
<dialog id="search-dialog">
|
|
290
|
+
<div class="container">
|
|
291
|
+
<form action="${this.hasAttribute('data-search') ? this.getAttribute('data-search') : ''}" class="row" id="search-form">
|
|
292
|
+
<div class="col mb-0 ms-auto col-md-7">
|
|
293
|
+
<label for="search" class="visually-hidden">Search</label>
|
|
294
|
+
<button class="suffix me-0 mb-0"><i class="fa-regular fa-search"></i></button>
|
|
295
|
+
<input type="search" class="" id="search" name="search" required="" autocomplete="off" data-list="${this.hasAttribute('data-list') ? this.getAttribute('data-list') : ''}" />
|
|
296
|
+
</div>
|
|
297
|
+
<div class="col d-none d-md-block mw-fit-content ms-3">
|
|
298
|
+
<button class="btn btn-compact btn-secondary fa-xmark-large m-0 mb-0" type="button" id="search-close"></button>
|
|
299
|
+
</div>
|
|
300
|
+
</form>
|
|
301
|
+
</div>
|
|
302
|
+
</dialog>`);
|
|
303
|
+
|
|
304
|
+
let searchButton = this.shadowRoot.querySelector('#search-button');
|
|
305
|
+
let searchClose = this.shadowRoot.querySelector('#search-close');
|
|
306
|
+
let searchDialog = this.shadowRoot.querySelector('#search-dialog');
|
|
307
|
+
let searchInput = this.shadowRoot.querySelector('#search');
|
|
308
|
+
let searchForm = this.shadowRoot.querySelector('#search-form');
|
|
309
|
+
|
|
310
|
+
if(this.hasAttribute('data-search-open')){
|
|
311
|
+
|
|
312
|
+
searchDialog.setAttribute('open','open');
|
|
313
|
+
this.classList.add('search-open');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
searchButton.addEventListener("click", (event) => {
|
|
317
|
+
|
|
318
|
+
searchDialog.setAttribute('open','open');
|
|
319
|
+
this.classList.add('search-open');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
searchClose.addEventListener("click", (event) => {
|
|
323
|
+
|
|
324
|
+
searchDialog.removeAttribute('open');
|
|
325
|
+
this.classList.remove('search-open');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// Search events
|
|
329
|
+
searchInput.addEventListener('keydown', (event) => {
|
|
330
|
+
|
|
331
|
+
const keyupEvent = new CustomEvent("search-keydown", { detail: { search: searchInput.value } });
|
|
332
|
+
this.dispatchEvent(keyupEvent);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
searchInput.addEventListener('keyup', (event) => {
|
|
336
|
+
|
|
337
|
+
if (searchInput.value.length >= 3 && searchInput.hasAttribute('data-list'))
|
|
338
|
+
searchInput.setAttribute("list", searchInput.getAttribute('data-list'));
|
|
339
|
+
else
|
|
340
|
+
searchInput.removeAttribute("list");
|
|
341
|
+
|
|
342
|
+
const keyupEvent = new CustomEvent("search-keyup", { detail: { search: searchInput.value } });
|
|
343
|
+
this.dispatchEvent(keyupEvent);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
searchInput.addEventListener('change', (event) => {
|
|
347
|
+
|
|
348
|
+
const changeEvent = new CustomEvent("search-change", { detail: { search: searchInput.value } });
|
|
349
|
+
this.dispatchEvent(changeEvent);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
searchForm.addEventListener('submit', (event) => {
|
|
353
|
+
|
|
354
|
+
if(this.hasAttribute('data-prevent-search'))
|
|
355
|
+
event.preventDefault();
|
|
356
|
+
|
|
357
|
+
const submitEvent = new CustomEvent("search-submit", { detail: { search: searchInput.value } });
|
|
358
|
+
this.dispatchEvent(submitEvent);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// Make sure any child lists are available to the search input
|
|
362
|
+
this.querySelectorAll('datalist').forEach((list) => {
|
|
363
|
+
|
|
364
|
+
iamNav.shadowRoot.querySelector('.lists').insertAdjacentElement('beforeend',list);
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export default iamNav;
|
|
@@ -27,6 +27,7 @@ class iamTable extends HTMLElement {
|
|
|
27
27
|
|
|
28
28
|
${this.hasAttribute('css') ? `@import "${this.getAttribute('css')}";` : ``}
|
|
29
29
|
</style>
|
|
30
|
+
<slot name="before"></slot>
|
|
30
31
|
<div class="table--cta">
|
|
31
32
|
<div class="table__wrapper">
|
|
32
33
|
<slot></slot>
|
|
@@ -124,6 +125,70 @@ class iamTable extends HTMLElement {
|
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
});
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
// Add in the checkboxes
|
|
131
|
+
|
|
132
|
+
if(this.querySelector('iam-actionbar[data-selectall]')){
|
|
133
|
+
|
|
134
|
+
const actionbar = this.querySelector('iam-actionbar[data-selectall]');
|
|
135
|
+
|
|
136
|
+
Array.from(this.table.querySelectorAll('thead tr')).forEach((row,index) => {
|
|
137
|
+
|
|
138
|
+
row.insertAdjacentHTML(
|
|
139
|
+
'afterbegin',
|
|
140
|
+
"<th></th>"
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
Array.from(this.table.querySelectorAll('tbody tr')).forEach((row,index) => {
|
|
145
|
+
|
|
146
|
+
row.insertAdjacentHTML(
|
|
147
|
+
'afterbegin',
|
|
148
|
+
`<td class="selectrow"><input type="checkbox" name="row" id="row${index}"/><label for="row${index}"><span class="visually-hidden">Select row</span></label></td>`
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
this.table.addEventListener('change',(event) => {
|
|
153
|
+
|
|
154
|
+
if (event && event.target instanceof HTMLElement && event.target.closest('.selectrow input')){
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
let count = this.table.querySelectorAll('.selectrow input[type="checkbox"]').length;
|
|
158
|
+
let countChecked = this.table.querySelectorAll('.selectrow input[type="checkbox"]:checked').length;
|
|
159
|
+
|
|
160
|
+
actionbar.setAttribute('data-selected', count == countChecked ? "all" : countChecked);
|
|
161
|
+
|
|
162
|
+
console.log(countChecked);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
actionbar.addEventListener('selected', (event) => {
|
|
168
|
+
|
|
169
|
+
console.log(event.detail.selected);
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if(event.detail.selected == '0'){
|
|
173
|
+
|
|
174
|
+
Array.from(this.table.querySelectorAll('.selectrow input[type="checkbox"]')).forEach((input,index) => {
|
|
175
|
+
|
|
176
|
+
input.checked = false;
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
else if(event.detail.selected == 'all'){
|
|
181
|
+
|
|
182
|
+
Array.from(this.table.querySelectorAll('.selectrow input[type="checkbox"]')).forEach((input,index) => {
|
|
183
|
+
|
|
184
|
+
input.checked = true;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
}
|
|
127
192
|
}
|
|
128
193
|
|
|
129
194
|
|
|
@@ -20,6 +20,9 @@ const extendDialogs = (body) => {
|
|
|
20
20
|
// Dialogs/modals
|
|
21
21
|
body.addEventListener('click', (event) => {
|
|
22
22
|
|
|
23
|
+
if(event.target.tagName == 'IAM-ACTIONBAR')
|
|
24
|
+
return false;
|
|
25
|
+
|
|
23
26
|
// Modal
|
|
24
27
|
if (event && event.target instanceof HTMLElement && event.target.closest('[data-modal]')){
|
|
25
28
|
|
|
@@ -77,7 +80,12 @@ const extendDialogs = (body) => {
|
|
|
77
80
|
|
|
78
81
|
// Close the modal when clicked on the backdrop
|
|
79
82
|
if (event && event.target instanceof HTMLElement && event.target.closest('dialog[open]')){
|
|
80
|
-
|
|
83
|
+
let dialog = event.target.closest('dialog[open]');
|
|
84
|
+
|
|
85
|
+
// Small fix to make sure the dialog isn't a dialog inside of a dialog.
|
|
86
|
+
var style = window.getComputedStyle(dialog);
|
|
87
|
+
if(style.display === 'contents')
|
|
88
|
+
dialog = dialog.parentNode.closest('dialog[open]');
|
|
81
89
|
|
|
82
90
|
// Dont allow the backdrop to be clicked when transactional
|
|
83
91
|
if(!dialog.querySelector(':scope > .mh-lg > form:last-child > button:last-child, :scope > .mh-lg > button:last-child') || dialog.classList.contains('dialog--multi')){
|
|
@@ -101,13 +109,16 @@ const extendDialogs = (body) => {
|
|
|
101
109
|
// Popover
|
|
102
110
|
if (event && event.target instanceof HTMLElement && event.target.closest('.dialog__wrapper > button')){
|
|
103
111
|
|
|
112
|
+
|
|
113
|
+
event.stopPropagation();
|
|
114
|
+
|
|
104
115
|
let btn = event.target.closest('.dialog__wrapper > button');
|
|
105
116
|
let parent = event.target.closest('.dialog__wrapper > button').parentNode;
|
|
106
117
|
let dataEvent = "openPopover"
|
|
107
118
|
let popover = parent.querySelector(':scope > dialog');
|
|
108
119
|
|
|
109
|
-
if(document.querySelector('dialog[open]') && document.querySelector('dialog[open]') != popover)
|
|
110
|
-
document.querySelector('dialog[open]').close();
|
|
120
|
+
if(document.querySelector('*:not([data-keep-open]) > dialog[open]') && document.querySelector('*:not([data-keep-open]) > dialog[open]') != popover)
|
|
121
|
+
document.querySelector('*:not([data-keep-open]) > dialog[open]').close();
|
|
111
122
|
|
|
112
123
|
// Remove active class from exiting active buttons
|
|
113
124
|
Array.from(document.querySelectorAll('.dialog__wrapper > button')).forEach((btnElement,index) => {
|
|
@@ -152,8 +163,14 @@ const extendDialogs = (body) => {
|
|
|
152
163
|
if(popoverBottom > windowPos){
|
|
153
164
|
|
|
154
165
|
let currentStyle = popover.hasAttribute('style') ? popover.getAttribute('style')+' ' : '';
|
|
155
|
-
|
|
156
166
|
popover.setAttribute('style',currentStyle+`transform: translate(0, calc(-100% - 4rem))`);
|
|
167
|
+
|
|
168
|
+
// Check that the dialog doesn't go over the top of the page
|
|
169
|
+
boundingRec = popover.getBoundingClientRect();
|
|
170
|
+
let popoverTop = boundingRec.top - window.scrollY;
|
|
171
|
+
|
|
172
|
+
if(popoverTop < 100)
|
|
173
|
+
popover.removeAttribute('style');
|
|
157
174
|
}
|
|
158
175
|
|
|
159
176
|
window.dataLayer = window.dataLayer || [];
|
|
@@ -199,6 +216,7 @@ export const createDialog = (dialog) => {
|
|
|
199
216
|
createMultiFormDialog(dialog);
|
|
200
217
|
}
|
|
201
218
|
|
|
219
|
+
// If you are using Vue eevents and bindings its recommended to add in the .mh-lg div manually to the dialog
|
|
202
220
|
if(!dialog.querySelector(':scope > .mh-lg') && !dialog.classList.contains('dialog--multi')){
|
|
203
221
|
dialog.innerHTML = `<div class="mh-lg">${dialog.innerHTML}</div>`;
|
|
204
222
|
|
|
@@ -218,7 +236,7 @@ export const createDialog = (dialog) => {
|
|
|
218
236
|
|
|
219
237
|
// Create close button is needed
|
|
220
238
|
if(!dialog.querySelector(':scope > button:first-child'))
|
|
221
|
-
dialog.
|
|
239
|
+
dialog.insertAdjacentHTML('afterbegin', `<button class="dialog__close">Close</button>`);
|
|
222
240
|
|
|
223
241
|
}
|
|
224
242
|
|
|
@@ -244,7 +262,7 @@ export const createMultiFormDialog = (dialog) => {
|
|
|
244
262
|
btnWrapper.innerHTML += `<button data-title="${fieldsets[index].getAttribute('data-title')}" class="btn btn-primary mb-0" data-next type="submit">Submit</button>`;
|
|
245
263
|
});
|
|
246
264
|
|
|
247
|
-
dialog.
|
|
265
|
+
dialog.insertAdjacentHTML('afterbegin',`<div class="steps bg-primary">${buttons}</div>`);
|
|
248
266
|
|
|
249
267
|
|
|
250
268
|
// Open the fieldset with an error inside
|
|
@@ -456,12 +456,23 @@ export const filterTable = (table, form, wrapper) => {
|
|
|
456
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
|
|
|
@@ -944,7 +966,7 @@ export const loadAjaxTable = async function (table, form, pagination, wrapper){
|
|
|
944
966
|
wrapper.setAttribute('data-pages', Math.ceil(wrapper.getAttribute('data-total') / wrapper.getAttribute('data-show')));
|
|
945
967
|
|
|
946
968
|
|
|
947
|
-
makeTableFunctional(table, form, pagination, wrapper);
|
|
969
|
+
makeTableFunctional(table, form, pagination, wrapper);
|
|
948
970
|
createPaginationButttons(wrapper, pagination);
|
|
949
971
|
|
|
950
972
|
Array.from(form.querySelectorAll('[data-ajax-query]')).forEach((queryElement, index) => {
|