@elrayes/dynamic-form-builder
Version:
A flexible and customizable dynamic form builder with theming support
341 lines • 11.7 kB
JavaScript
/**
* Tailwind CSS theme implementation
*/
import Theme from './Theme.js';
export default class TailwindTheme extends Theme {
/**
* Get form class names
* @returns {string}
*/
getFormClasses() {
return '';
}
/**
* Get form group class names
* @returns {string}
*/
getFormGroupClasses() {
return 'mb-4';
}
/**
* Get label class names
* @returns {string}
*/
getLabelClasses() {
return 'block text-sm font-medium text-gray-700 mb-1';
}
/**
* Get input class names
* @param {string} type - Input type (text, email, password, etc.)
* @returns {string}
*/
getInputClasses(type) {
return 'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm';
}
/**
* Get select class names
* @param {boolean} multiple - Whether the select is multiple
* @returns {string}
*/
getSelectClasses(multiple = false) {
return 'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm';
}
/**
* Get textarea class names
* @returns {string}
*/
getTextareaClasses() {
return 'mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm';
}
/**
* Get checkbox container class names
* @returns {string}
*/
getCheckboxContainerClasses() {
return 'flex items-start';
}
/**
* Get checkbox input class names
* @returns {string}
*/
getCheckboxInputClasses() {
return 'h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500';
}
/**
* Get checkbox label class names
* @returns {string}
*/
getCheckboxLabelClasses() {
return 'ml-2 block text-sm text-gray-700';
}
/**
* Get radio container class names
* @returns {string}
*/
getRadioContainerClasses() {
return 'flex items-center mr-4';
}
/**
* Get radio input class names
* @returns {string}
*/
getRadioInputClasses() {
return 'h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-500';
}
/**
* Get radio label class names
* @returns {string}
*/
getRadioLabelClasses() {
return 'ml-2 block text-sm text-gray-700';
}
/**
* Get submit button class names
* @returns {string}
*/
getSubmitButtonClasses() {
return 'inline-flex justify-center rounded-md border border-transparent bg-indigo-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 mt-4';
}
/**
* Get validation error message class names
* @returns {string}
*/
getValidationErrorClasses() {
return 'mt-2 text-sm text-red-600';
}
/**
* Get helper text class names
* @returns {string}
*/
getHelperTextClasses() {
return 'mt-1 text-sm text-gray-500';
}
/**
* Get modal class names
* @returns {string}
*/
getModalClasses() {
return 'fixed inset-0 z-10 overflow-y-auto';
}
/**
* Get modal dialog class names
* @returns {string}
*/
getModalDialogClasses() {
return 'flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0';
}
/**
* Get modal content class names
* @returns {string}
*/
getModalContentClasses() {
return 'relative transform overflow-hidden rounded-lg bg-white text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg';
}
/**
* Get modal header class names
* @returns {string}
*/
getModalHeaderClasses() {
return 'bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4';
}
/**
* Get modal title class names
* @returns {string}
*/
getModalTitleClasses() {
return 'text-lg font-medium leading-6 text-gray-900';
}
/**
* Get modal close button class names
* @returns {string}
*/
getModalCloseButtonClasses() {
return 'absolute top-3 right-2.5 text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm p-1.5 ml-auto inline-flex items-center';
}
/**
* Get modal body class names
* @returns {string}
*/
getModalBodyClasses() {
return 'bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4';
}
/**
* Get invalid input class names
* @returns {string}
*/
getInvalidInputClasses() {
return 'border-red-500 focus:border-red-500 focus:ring-red-500';
}
/**
* Get valid input class names
* @returns {string}
*/
getValidInputClasses() {
return 'border-green-500 focus:border-green-500 focus:ring-green-500';
}
/**
* Get file info container class names
* @returns {string}
*/
getFileInfoClasses() {
return 'mt-2';
}
/**
* Get file thumbnail class names
* @returns {string}
*/
getFileThumbnailClasses() {
return 'max-w-[150px] rounded-md border border-gray-300';
}
/**
* Get file info text class names
* @returns {string}
*/
getFileInfoTextClasses() {
return 'text-sm text-gray-500';
}
/**
* Creates a modal and returns the modal body element for mounting the form
* @param {ModalOptions} modalOptions - Modal options (id, title, etc.)
* @returns {ModalCreationResult} - Object containing the modal element and the modal body element
*/
createModal(modalOptions) {
// Generate modal structure with Tailwind CSS classes
const modal = document.createElement('div');
modal.className = this.getModalClasses();
modal.id = modalOptions.id || '';
modal.tabIndex = -1;
if (modalOptions.title) {
modal.ariaLabel = modalOptions.title;
}
modal.ariaHidden = "true";
// Create backdrop
const backdrop = document.createElement('div');
backdrop.className = 'fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity';
modal.appendChild(backdrop);
// Create dialog container
const dialogContainer = document.createElement('div');
dialogContainer.className = this.getModalDialogClasses();
modal.appendChild(dialogContainer);
// Create content container
const contentContainer = document.createElement('div');
contentContainer.className = this.getModalContentClasses();
dialogContainer.appendChild(contentContainer);
// Create header
const header = document.createElement('div');
header.className = this.getModalHeaderClasses();
contentContainer.appendChild(header);
// Create title
const title = document.createElement('h3');
title.className = this.getModalTitleClasses();
title.textContent = modalOptions.title || '';
header.appendChild(title);
// Create close button
const closeButton = document.createElement('button');
closeButton.type = 'button';
closeButton.className = this.getModalCloseButtonClasses();
closeButton.setAttribute('data-dismiss', 'modal');
header.appendChild(closeButton);
// Add close icon
closeButton.innerHTML = `
<span class="sr-only">Close</span>
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
`;
// Create body
const body = document.createElement('div');
body.className = this.getModalBodyClasses();
contentContainer.appendChild(body);
document.body.appendChild(modal);
return {
modal: modal,
modalBody: body
};
}
/**
* Initializes the modal and returns the modal instance
* @param {HTMLElement} modal - The modal element
* @param {ModalOptions} options - Modal initialization options
* @returns {ModalInstance} - The modal instance
*/
initializeModal(modal, options) {
// Tailwind doesn't have built-in modal functionality, so we implement it ourselves
// Add event listener to close button
const closeButton = modal.querySelector('button[data-dismiss="modal"]');
if (closeButton) {
closeButton.addEventListener('click', () => {
this.hideModal(modal);
});
}
// Add event listener for ESC key to close modal
const escKeyHandler = (e) => {
if (e.key === 'Escape' && modal && !modal.classList.contains('hidden')) {
this.hideModal(modal);
}
};
document.addEventListener('keydown', escKeyHandler);
// Add event listener for backdrop click to close modal
const backdrop = modal.querySelector('.fixed.inset-0');
if (backdrop && !options?.staticBackdrop) {
backdrop.addEventListener('click', (e) => {
if (e.target === backdrop) {
this.hideModal(modal);
}
});
}
// Return an object with show/hide methods
return {
show: () => this.showModal(modal),
hide: () => this.hideModal(modal),
toggle: () => modal.classList.contains('hidden') ? this.showModal(modal) : this.hideModal(modal),
dispose: () => {
modal.remove();
},
getInstance: () => null // No instance in Tailwind
};
}
// Helper methods for Tailwind modal
showModal(modal) {
if (!modal)
return;
modal.classList.remove('hidden');
document.body.classList.add('overflow-hidden');
// Trigger animation
setTimeout(() => {
const backdrop = modal.querySelector('.fixed.inset-0');
if (backdrop) {
backdrop.classList.remove('opacity-0');
backdrop.classList.add('opacity-100');
}
const dialog = modal.querySelector('.' + this.getModalDialogClasses().split(' ')[0]);
if (dialog) {
dialog.classList.remove('opacity-0', 'translate-y-4', 'sm:translate-y-0', 'sm:scale-95');
dialog.classList.add('opacity-100', 'translate-y-0', 'sm:scale-100');
}
}, 10);
modal.dispatchEvent(new CustomEvent('modal:shown'));
}
hideModal(modal) {
if (!modal)
return;
// Trigger animation
const backdrop = modal.querySelector('.fixed.inset-0');
if (backdrop) {
backdrop.classList.remove('opacity-100');
backdrop.classList.add('opacity-0');
}
const dialog = modal.querySelector('.' + this.getModalDialogClasses().split(' ')[0]);
if (dialog) {
dialog.classList.remove('opacity-100', 'translate-y-0', 'sm:scale-100');
dialog.classList.add('opacity-0', 'translate-y-4', 'sm:translate-y-0', 'sm:scale-95');
}
// Hide after animation
setTimeout(() => {
modal.classList.add('hidden');
document.body.classList.remove('overflow-hidden');
modal.dispatchEvent(new CustomEvent('modal:hidden'));
}, 300);
}
}
//# sourceMappingURL=TailwindTheme.js.map