styleui-components
Version:
Lightweight, modular UI component library with zero dependencies
102 lines (87 loc) • 3.48 kB
JavaScript
(function() {
if (!window.UI) window.UI = {};
/**
* Shows a modal dialog.
* @param {string|HTMLElement} content - The HTML string or element for the modal body.
* @param {object} [options={}] - Options for the modal.
* @param {string} [options.title] - The title for the modal header.
* @param {string} [options.icon] - Lucide icon name for the header.
* @param {string} [options.size] - The size variant (e.g., 'sm', 'lg').
* @param {Array<object>} [options.actions] - Action buttons for the footer.
* @param {boolean} [options.closeOnBackdrop=true] - If the modal should close when clicking the backdrop.
* @param {function} [options.onclose] - Callback function when the modal is closed.
* @returns {{modal: HTMLElement, backdrop: HTMLElement, close: function}} The modal elements and close function.
*/
UI.modal = function(config = {}) {
const {
content,
title = '',
icon,
size,
actions = [],
closeOnBackdrop = true,
onclose
} = config;
const modal = document.createElement('div');
modal.className = this.buildClasses('modal', size && `modal-${size}`);
const backdrop = document.createElement('div');
backdrop.className = 'modal-backdrop';
let cardFooter = null;
if (actions.length > 0) {
cardFooter = document.createElement('div');
// The card component will add its own footer class.
actions.forEach(action => {
const btn = this.button(action.text, {
variant: action.variant,
size: action.size,
onclick: () => {
if (action.onclick) action.onclick();
if (action.closeModal !== false) closeModal();
}
});
cardFooter.appendChild(btn);
});
}
const card = UI.card({
title,
content,
icon,
footer: cardFooter,
actions: title ? [{
icon: 'x',
onclick: () => closeModal(),
ariaLabel: 'Close'
}] : null
});
modal.appendChild(card);
backdrop.appendChild(modal);
document.body.appendChild(backdrop);
this.icons();
requestAnimationFrame(() => {
backdrop.classList.add('show');
modal.classList.add('show');
});
const closeModal = () => {
backdrop.classList.remove('show');
modal.classList.remove('show');
// Allow animation to complete before removing from DOM
setTimeout(() => {
backdrop.remove();
document.removeEventListener('keydown', escapeHandler);
}, CONFIG.MODAL_ANIMATION_DURATION); // Match this with --transition-base
if (onclose) onclose();
};
const escapeHandler = (e) => {
if (e.key === 'Escape') {
closeModal();
}
};
backdrop.onclick = (e) => {
if (e.target === backdrop && closeOnBackdrop) {
closeModal();
}
};
document.addEventListener('keydown', escapeHandler);
return { modal, backdrop, close: closeModal };
};
})();