import { createVNode, DirectiveBinding, ObjectDirective, render } from 'vue' import ValidationError from '~/pages/widgets/ValidationError.vue' interface ValidationErrorBinding extends DirectiveBinding { value: string | null } const validationErrorDirective: ObjectDirective = { mounted(el: HTMLElement, binding: ValidationErrorBinding) { const errorMessage = binding.value const fieldName = el.getAttribute('name') if (errorMessage && fieldName) { const container = document.createElement('div') container.classList.add(`validation-error-container-${fieldName}`) container.classList.add( 'transition-all', 'duration-2500', 'ease-in-out', 'w-0', 'opacity-0' ) // Ajout des classes Tailwind pour la transition container.style.position = 'absolute' container.style.bottom = '-17px' container.style.right = '0px' container.style.whiteSpace = 'nowrap' container.style.textAlign = 'right' if (el.parentNode && el.parentNode instanceof HTMLElement) { el.parentNode.style.position = 'relative' el.parentNode.appendChild(container) const vnode = createVNode(ValidationError, { message: errorMessage }) render(vnode, container) // Force reflow pour d├®clencher la transition void container.offsetWidth container.classList.remove('w-0', 'opacity-0') container.classList.add('w-full', 'opacity-100') // Attach the container to the element for future reference ;(el as any)._validationErrorContainer = container } else { console.error('Parent node is null or not an HTMLElement during mounted') } } }, updated(el: HTMLElement, binding: ValidationErrorBinding) { const errorMessage = binding.value const fieldName = el.getAttribute('name') let container = (el as any)._validationErrorContainer if (errorMessage && fieldName) { if (container) { const vnode = createVNode(ValidationError, { message: errorMessage }) render(vnode, container) } else { const newContainer = document.createElement('div') newContainer.classList.add(`validation-error-container-${fieldName}`) newContainer.classList.add( 'transition-all', 'duration-2500', 'ease-in-out', 'w-0', 'opacity-0' ) // Ajout des classes Tailwind pour la transition newContainer.style.position = 'absolute' newContainer.style.bottom = '-17px' newContainer.style.right = '0px' newContainer.style.whiteSpace = 'nowrap' newContainer.style.textAlign = 'right' if (el.parentNode && el.parentNode instanceof HTMLElement) { el.parentNode.style.position = 'relative' el.parentNode.appendChild(newContainer) const vnode = createVNode(ValidationError, { message: errorMessage }) render(vnode, newContainer) // Force reflow pour d├®clencher la transition void newContainer.offsetWidth newContainer.classList.remove('w-0', 'opacity-0') newContainer.classList.add('w-100', 'opacity-100') // Attach the container to the element for future reference ;(el as any)._validationErrorContainer = newContainer } else { console.error('Parent node is null or not an HTMLElement during updated') } } } else if (container) { container.classList.remove('w-100', 'opacity-100') container.classList.remove('transition-all', 'duration-2500', 'ease-in-out') // Supprimez les classes de transition pour la disparition container.classList.add('w-0', 'opacity-0') // Supprimez le conteneur imm├®diatement sans d├®lai render(null, container) container.remove() ;(el as any)._validationErrorContainer = null } }, unmounted(el: HTMLElement) { // Clean up the error container when the element is unmounted const container = (el as any)._validationErrorContainer if (container) { render(null, container) container.remove() } }, } export default validationErrorDirective