|
71 | 71 | const isTopBranch = !triggerElement.classList.contains('ibexa-popup-menu__item'); |
72 | 72 | const branchItems = this.getBranchItems(branchElement); |
73 | 73 | const offset = isTopBranch ? [0, 3] : [-8, 2]; |
| 74 | + const branchSearchInput = branchElement.querySelector('.ibexa-multilevel-popup-menu__search-input'); |
74 | 75 |
|
75 | 76 | const popperInstance = Popper.createPopper(referenceElement ?? triggerElement, branchElement, { |
76 | 77 | placement, |
|
91 | 92 | ], |
92 | 93 | }); |
93 | 94 |
|
| 95 | + branchSearchInput.addEventListener('keyup', this.filterBranchItems, false); |
| 96 | + branchSearchInput.addEventListener('input', this.filterBranchItems, false); |
94 | 97 | branchElement.popperInstance = popperInstance; |
95 | 98 |
|
96 | 99 | if (isTopBranch) { |
|
151 | 154 | } |
152 | 155 |
|
153 | 156 | updateBranchOpenState(branchElement) { |
| 157 | + const searchInput = branchElement.querySelector('.ibexa-multilevel-popup-menu__search-input'); |
| 158 | + const isSearchInputFilled = !!searchInput?.value; |
154 | 159 | const isSubbranchOpened = (otherBranchElement) => { |
155 | 160 | return ( |
156 | 161 | otherBranchElement && |
|
159 | 164 | }; |
160 | 165 | const isBranchOrAnySubbranchHovered = [...this.hoveredItemsBranches, ...this.hoveredBranches].some(isSubbranchOpened); |
161 | 166 |
|
162 | | - if (isBranchOrAnySubbranchHovered) { |
| 167 | + if (isBranchOrAnySubbranchHovered || isSearchInputFilled) { |
163 | 168 | this.openBranch(branchElement); |
164 | 169 | } else { |
165 | 170 | this.closeWithSubbranches(branchElement); |
|
213 | 218 | } |
214 | 219 |
|
215 | 220 | generateMenu(menuTree) { |
216 | | - const { triggerElement, groups, placement, fallbackPlacements, processAfterCreated: processBranchAfterCreated } = menuTree; |
| 221 | + const { |
| 222 | + triggerElement, |
| 223 | + groups, |
| 224 | + placement, |
| 225 | + fallbackPlacements, |
| 226 | + processAfterCreated: processBranchAfterCreated, |
| 227 | + hasSearch, |
| 228 | + } = menuTree; |
217 | 229 |
|
218 | 230 | const branchElement = this.generateBranch( |
219 | 231 | { |
220 | 232 | triggerElement, |
221 | 233 | placement, |
222 | 234 | fallbackPlacements, |
| 235 | + hasSearch, |
223 | 236 | }, |
224 | 237 | processBranchAfterCreated, |
225 | 238 | ); |
|
250 | 263 | } |
251 | 264 |
|
252 | 265 | generateBranch(data, processAfterCreated = () => {}) { |
253 | | - const { triggerElement, placement, fallbackPlacements } = data; |
| 266 | + const { triggerElement, placement, fallbackPlacements, hasSearch = false } = data; |
254 | 267 | const { branchTemplate } = this.container.dataset; |
255 | 268 |
|
256 | 269 | const container = doc.createElement('div'); |
|
259 | 272 | container.insertAdjacentHTML('beforeend', renderedItem); |
260 | 273 |
|
261 | 274 | const newBranchElement = container.querySelector('.ibexa-multilevel-popup-menu__branch'); |
| 275 | + const searchInputWrapper = newBranchElement.querySelector('.ibexa-multilevel-popup-menu__search'); |
| 276 | + |
| 277 | + searchInputWrapper.classList.toggle('ibexa-multilevel-popup-menu__search--hidden', !hasSearch); |
262 | 278 |
|
263 | 279 | processAfterCreated(newBranchElement, data); |
264 | 280 |
|
|
304 | 320 |
|
305 | 321 | processAfterCreated(newGroupElement, data); |
306 | 322 |
|
307 | | - branchElement.appendChild(newGroupElement); |
| 323 | + const newGroupContainer = branchElement.querySelector('.ibexa-multilevel-popup-menu__groups'); |
| 324 | + |
| 325 | + newGroupContainer.appendChild(newGroupElement); |
308 | 326 |
|
309 | 327 | return newGroupElement; |
310 | 328 | } |
|
365 | 383 | return; |
366 | 384 | } |
367 | 385 |
|
| 386 | + const { target } = event; |
368 | 387 | const isPopupMenuExpanded = !topBranch.classList.contains('ibexa-popup-menu--hidden'); |
369 | | - const isClickInsideTrigger = this.triggerElement.contains(event.target); |
| 388 | + const isClickInsideTrigger = this.triggerElement.contains(target); |
| 389 | + const isTargetBranch = target.classList.contains('ibexa-multilevel-popup-menu__branch'); |
| 390 | + const targetBranch = target.closest('.ibexa-multilevel-popup-menu__branch'); |
| 391 | + const isClickInsideMenu = isTargetBranch || !!targetBranch; |
370 | 392 |
|
371 | | - if (!isPopupMenuExpanded || isClickInsideTrigger) { |
| 393 | + if (!isPopupMenuExpanded || isClickInsideTrigger || isClickInsideMenu) { |
372 | 394 | return; |
373 | 395 | } |
374 | 396 |
|
| 397 | + const branchsSearchInput = doc.querySelectorAll('.ibexa-multilevel-popup-menu__search-input'); |
| 398 | + |
| 399 | + branchsSearchInput.forEach((searchInput) => { |
| 400 | + if (searchInput.value !== '') { |
| 401 | + const searchInputBranch = searchInput.closest('.ibexa-multilevel-popup-menu__branch'); |
| 402 | + |
| 403 | + searchInput.value = ''; |
| 404 | + searchInputBranch.dispatchEvent(new Event('mouseleave')); |
| 405 | + searchInput.dispatchEvent(new Event('input')); |
| 406 | + } |
| 407 | + }); |
| 408 | + |
375 | 409 | this.closeWithSubbranches(topBranch); |
376 | 410 | } |
| 411 | + |
| 412 | + filterBranchItems(event) { |
| 413 | + const searchInput = event.currentTarget; |
| 414 | + const branch = searchInput.closest('.ibexa-multilevel-popup-menu__branch'); |
| 415 | + const branchItems = branch.querySelectorAll('.ibexa-popup-menu__group > .ibexa-popup-menu__item'); |
| 416 | + const phraseLowerCase = searchInput.value.toLowerCase(); |
| 417 | + |
| 418 | + branchItems.forEach((item) => { |
| 419 | + const { label } = item.dataset; |
| 420 | + const labelLowerCase = label.toLowerCase(); |
| 421 | + const hideItem = !labelLowerCase.includes(phraseLowerCase); |
| 422 | + |
| 423 | + item.classList.toggle('ibexa-popup-menu__item--hidden', hideItem); |
| 424 | + }); |
| 425 | + } |
377 | 426 | } |
378 | 427 |
|
379 | 428 | ibexa.addConfig('core.MultilevelPopupMenu', MultilevelPopupMenu); |
|
0 commit comments