UNPKG

lumecss

Version:

LumeCss is a modern, lightweight, and flexible CSS library designed for building fast and responsive user interfaces. Built with SCSS and TypeScript, LumeCss provides utility-first classes, customizable themes, and reusable components to speed up your dev

239 lines (192 loc) 9.37 kB
// Get the NodeList of dropdown objects const dropdownElements: NodeListOf<HTMLElement> = document.querySelectorAll('.dropdown'); // Convert the NodeList to an array const dropdownElementsArray: HTMLElement[] = Array.from(dropdownElements); /* Iterate over each dropdown element in the dropdownElementsArray to give an event listener to each dropdown-toggle button */ dropdownElementsArray.forEach((element: HTMLElement):void => { /* Get the value of the data-close-previous attribute from the dropdown wrapper. By default, this is set to true. However, if it is set to false, every time the user tries to collapse the dropdown, a function will be triggered to deactivate any previously opened dropdowns. */ const closePrevious: boolean = element ? element.getAttribute('data-close-previous') === 'true' : false; // Get the dropdown-toggle button const dropdownToggleBtn = element.querySelector('.dropdown-toggle') as HTMLButtonElement; // Get the dropdown menu or null const dropdownMenu: HTMLElement | null = element.querySelector('.dropdown-menu'); // Check if the toggle button and dropdown menu exist if (dropdownToggleBtn && dropdownMenu) { /* Get the button attribute 'data-dropdown-trigger'. * It indicates how the dropdown will be collapsed. * The value can be either 'click' or 'hover-click'. * It is 'click' by default */ const dropdown_trigger: string = dropdownToggleBtn.getAttribute('data-dropdown-trigger') || 'click'; // Get the dropdown arrow button or null const dropdownArrowBtn: HTMLElement | null = dropdownToggleBtn.querySelector('.btn-arrow'); // Declare the dropdown size variable let dropdownMenuSize: number; // Retrieve the dropdown direction let dropdownMenuDirection: 'x' | 'y'; if (element.classList.contains('dropdown-left') || element.classList.contains('dropdown-right')) { dropdownMenuDirection = 'x'; // Get the dropdown menu width dropdownMenuSize = dropdownMenu.offsetWidth; } else { dropdownMenuDirection = 'y'; // Get the dropdown menu height dropdownMenuSize = dropdownMenu.offsetHeight; } /* It specifies whether the button can be closed after the mouse leaves. If the user collapses the dropdown using the button, it cannot be closed by mouseleave. However, if the user collapses the dropdown using mouseenter, it can be closed by mouseleave. */ let allowCloseByMouseLeave: boolean = false; // Add the eventListeners to the toggle button dropdownToggleBtn.addEventListener('click', (e: MouseEvent):void => { e.preventDefault(); // Make sure that the button is not disabled if (dropdownToggleBtn.classList.contains('disabled') || dropdownToggleBtn.disabled) return; // Check if the dropdown is already collapsed if (element.classList.contains('collapsed')) { // Hide the dropdown menu deactivateDropdownMenu( element, dropdownArrowBtn, dropdownMenu, dropdownMenuDirection ); } else { // Check if it is allowed to open multiple dropdowns if (closePrevious) { closeCollapsedDropdowns(); } // Show the dropdown menu collapseDropdownMenu( element, dropdownArrowBtn, dropdownMenu, dropdownMenuSize, dropdownMenuDirection ); // Assign false to the allowCloseByMouseLeave allowCloseByMouseLeave = false; } }); // Add the hover eventListeners to the toggle button if (dropdown_trigger === 'hover-click') { // Add the mouse enter eventListener dropdownToggleBtn.addEventListener('mouseenter', ():void => { // Ensure the dropdown is not collapsed if (element.classList.contains('collapsed')) return; // Make sure that the button is not disabled if (dropdownToggleBtn.classList.contains('disabled') || dropdownToggleBtn.disabled) return; // Show the dropdown menu collapseDropdownMenu( element, dropdownArrowBtn, dropdownMenu, dropdownMenuSize, dropdownMenuDirection ); // Assign true to the allowCloseByMouseLeave allowCloseByMouseLeave = true; }); // Add the mouse leave eventListener dropdownToggleBtn.addEventListener('mouseleave', ():void => { // Ensure the dropdown is already collapsed and allowCloseByMouseLeave is true if (!element.classList.contains('collapsed') || !allowCloseByMouseLeave) return; // Hide the dropdown menu deactivateDropdownMenu( element, dropdownArrowBtn, dropdownMenu, dropdownMenuDirection ); }); } } }); function closeCollapsedDropdowns(): void { /* The function deactivates all dropdowns which are collapsed */ // Retrieve the NodeList of collapsed dropdowns const collapsedDropdowns: NodeListOf<HTMLElement> = document.querySelectorAll('.dropdown.collapsed'); // Convert the NodeList to an array const collapsedDropdownsArray: HTMLElement[] = Array.from(collapsedDropdowns); // Iterate over each element in the collapsedDropdownsArray to deactivate it collapsedDropdownsArray.forEach((element: HTMLElement):void => { // Get the dropdown menu or null const dropdownMenu: HTMLElement | null = element.querySelector('.dropdown-menu'); // Get the dropdown arrow button or null const dropdownArrowBtn: HTMLElement | null = element.querySelector('.btn-arrow'); // Make sure that the dropdownMenu exists if (!dropdownMenu) return; // Retrieve the dropdown direction let dropdownMenuDirection: 'x' | 'y'; if (element.classList.contains('dropdown-left') || element.classList.contains('dropdown-right')) { dropdownMenuDirection = 'x'; } else { dropdownMenuDirection = 'y'; } // Deactivate the dropdown deactivateDropdownMenu(element, dropdownArrowBtn, dropdownMenu, dropdownMenuDirection); }); } function collapseDropdownMenu( dropdown: HTMLElement, dropdownArrowBtn: HTMLElement | null, dropdownMenu: HTMLElement, dropdownMenuSize: number, dropdownMenuDirection: 'x' | 'y', ):void { /* This function activates the dropdown menu. * Attributes: * - 'dropdown': The parent wrapper of the dropdown element. * - 'dropdownArrowBtn': The arrow button that indicates the dropdown can collapse. * - 'dropdownMenu': The dropdown menu element, which contains a list of links and tabs. * - 'dropdownMenuSize': The size of the dropdown menu. Used to make the dropdown animated * - 'dropdownMenuDirection': It specifies how we should collapse the menu list */ // Give the 'collapsed' class to the dropdown wrapper dropdown.classList.add('collapsed'); // Remove the height or width of the dropdownMenu to make it look animated if (dropdownMenuDirection === 'x') { dropdownMenu.style.width = '0'; } else { dropdownMenu.style.height = '0'; } // Ensure the dropdown arrow button exists and give it active class if (dropdownArrowBtn) { dropdownArrowBtn.classList.add('active'); } // Assign the dropdownMenuSize to the dropdownMenu after 10ms setTimeout(():void => { if (dropdownMenuDirection === 'x') { dropdownMenu.style.width = `${dropdownMenuSize}px` } else { dropdownMenu.style.height = `${dropdownMenuSize}px` } }, 10); } function deactivateDropdownMenu( dropdown: HTMLElement, dropdownArrowBtn: HTMLElement | null, dropdownMenu: HTMLElement, dropdownMenuDirection: 'x' | 'y', ):void { /* This function deactivates the dropdown menu. * Attributes: * - 'dropdown': The parent wrapper of the dropdown element. * - 'dropdownArrowBtn': The arrow button that indicates the dropdown can collapse. * - 'dropdownMenu': The dropdown menu element, which contains a list of links and tabs. * - 'dropdownMenuDirection': It specifies how we should close the menu list */ // Remove the height or width of the dropdownMenu to make it look animated if (dropdownMenuDirection === 'x') { dropdownMenu.style.width = `0`; } else { dropdownMenu.style.height = `0`; } // Ensure the dropdown arrow button exists and give it active class if (dropdownArrowBtn) { dropdownArrowBtn.classList.remove('active'); } // Remove the 'collapsed' class of the dropdown wrapper dropdown.classList.remove('collapsed'); }