tax-document-input
Version:
A vanilla JavaScript plugin for automatic formatting of tax documents from different countries (CPF, CNPJ, NIF, NIPC, SSN, EIN)
58 lines • 35.6 kB
JavaScript
/*!
* Tax Document Input Plugin v2.0.0
* Plugin JavaScript para formatação de documentos fiscais
*
* Copyright (c) 2025 Roni Sommerfeld
* Released under the MIT License
*
* Date: 2025-07-05
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).TaxDocumentInput={})}(this,function(t){"use strict";
/**
* Validator - Tax document validation system
* Manages validation rules by country and provides a unified validation interface
* @version 1.0.0
* @license MIT
* @author Roni Sommerfeld
* @module Validator
*/const e=new class{constructor(){this.rules=new Map,this.loadRules()}loadRules(){}registerRules(t,e){this.rules.set(t.toLowerCase(),e)}validate(t,e,n){const o=this.rules.get(e.toLowerCase());if(!o)return{isValid:!1,error:`Regras de validação não encontradas para o país: ${e}`,details:null};const i=o[n];if(!i||"function"!=typeof i)return{isValid:!1,error:`Validador não encontrado para o tipo: ${n}`,details:null};try{const o=i(t);return{isValid:o.isValid,error:o.error||null,details:o.details||null,documentType:n,countryCode:e}}catch(t){return{isValid:!1,error:`Erro durante validação: ${t.message}`,details:null}}}hasRules(t){return this.rules.has(t.toLowerCase())}getAvailableCountries(){return Array.from(this.rules.keys())}getSupportedDocuments(t){const e=this.rules.get(t.toLowerCase());return e?Object.keys(e):[]}};"undefined"!=typeof window&&(window.TaxDocumentValidator=e)
/**
* BrazilRules - Brazilian tax document validation rules
* Provides validation algorithms for CPF and CNPJ with correct check digit calculations
* @version 1.0.0
* @license MIT
* @author Roni Sommerfeld
* @module BrazilRules
* @requires ValidatorInstance
*/;const n={cpf:function(t){if(11!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"CPF deve conter exatamente 11 dígitos",details:{length:t.length,expected:11}};if(/^(\d)\1{10}$/.test(t))return{isValid:!1,error:"CPF não pode ter todos os dígitos iguais",details:{pattern:"repeated_digits"}};let e=0;for(let n=0;n<9;n++)e+=parseInt(t.charAt(n))*(10-n);let n=e%11,o=n<2?0:11-n;if(o!==parseInt(t.charAt(9)))return{isValid:!1,error:"Primeiro dígito verificador inválido",details:{calculated:o,provided:parseInt(t.charAt(9)),sum:e,remainder:n}};e=0;for(let n=0;n<10;n++)e+=parseInt(t.charAt(n))*(11-n);n=e%11;let i=n<2?0:11-n;return i!==parseInt(t.charAt(10))?{isValid:!1,error:"Segundo dígito verificador inválido",details:{calculated:i,provided:parseInt(t.charAt(10)),sum:e,remainder:n}}:{isValid:!0,error:null,details:{formatted:`${t.slice(0,3)}.${t.slice(3,6)}.${t.slice(6,9)}-${t.slice(9,11)}`,type:"personal",country:"BR"}}},cnpj:function(t){if(14!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"CNPJ deve conter exatamente 14 dígitos",details:{length:t.length,expected:14}};if(/^(\d)\1{13}$/.test(t))return{isValid:!1,error:"CNPJ não pode ter todos os dígitos iguais",details:{pattern:"repeated_digits"}};const e=[5,4,3,2,9,8,7,6,5,4,3,2];let n=0;for(let o=0;o<12;o++)n+=parseInt(t.charAt(o))*e[o];let o=n%11,i=o<2?0:11-o;if(i!==parseInt(t.charAt(12)))return{isValid:!1,error:"Primeiro dígito verificador inválido",details:{calculated:i,provided:parseInt(t.charAt(12)),sum:n,remainder:o}};const r=[6,5,4,3,2,9,8,7,6,5,4,3,2];n=0;for(let e=0;e<13;e++)n+=parseInt(t.charAt(e))*r[e];o=n%11;let a=o<2?0:11-o;return a!==parseInt(t.charAt(13))?{isValid:!1,error:"Segundo dígito verificador inválido",details:{calculated:a,provided:parseInt(t.charAt(13)),sum:n,remainder:o}}:{isValid:!0,error:null,details:{formatted:`${t.slice(0,2)}.${t.slice(2,5)}.${t.slice(5,8)}/${t.slice(8,12)}-${t.slice(12,14)}`,type:"company",country:"BR"}}}};e.registerRules("br",n),"undefined"!=typeof window&&window.TaxDocumentValidator&&window.TaxDocumentValidator.registerRules("br",n)
/**
* PortugalRules - Portuguese tax document validation rules
* Provides validation algorithms for NIF and NIPC with correct check digit calculations
* @version 1.0.0
* @license MIT
* @author Roni Sommerfeld
* @module PortugalRules
* @requires ValidatorInstance
*/;const o={nif:function(t){if(9!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"NIF must contain exactly 9 digits",details:{length:t.length,expected:9}};if(/^(\d)\1{8}$/.test(t))return{isValid:!1,error:"NIF cannot have all digits the same",details:{pattern:"repeated_digits"}};const e=["1","2","3","5","6","7","8","9"];if(!e.includes(t.charAt(0)))return{isValid:!1,error:"NIF must start with 1, 2, 3, 5, 6, 7, 8 or 9",details:{firstDigit:t.charAt(0),validFirstDigits:e}};const n=[9,8,7,6,5,4,3,2];let o=0;for(let e=0;e<8;e++)o+=parseInt(t.charAt(e))*n[e];const i=o%11;let r=11-i;if(i<2&&(r=0),r!==parseInt(t.charAt(8)))return{isValid:!1,error:"Invalid check digit",details:{calculated:r,provided:parseInt(t.charAt(8))}};const a=this.getEntityType(t.charAt(0));return{isValid:!0,error:null,details:{formatted:`${t.slice(0,3)} ${t.slice(3,6)} ${t.slice(6,9)}`,type:a,country:"PT"}}},nipc:function(t){if(9!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"NIPC must contain exactly 9 digits",details:{length:t.length,expected:9}};if(/^(\d)\1{8}$/.test(t))return{isValid:!1,error:"NIPC cannot have all digits the same",details:{pattern:"repeated_digits"}};const e=["5","6","7","8","9"];if(!e.includes(t.charAt(0)))return{isValid:!1,error:"NIPC must start with 5, 6, 7, 8 or 9",details:{firstDigit:t.charAt(0),validFirstDigits:e}};const n=[9,8,7,6,5,4,3,2];let o=0;for(let e=0;e<8;e++)o+=parseInt(t.charAt(e))*n[e];const i=o%11;let r=11-i;return i<2&&(r=0),r!==parseInt(t.charAt(8))?{isValid:!1,error:"Invalid check digit",details:{calculated:r,provided:parseInt(t.charAt(8))}}:{isValid:!0,error:null,details:{formatted:`${t.slice(0,3)} ${t.slice(3,6)} ${t.slice(6,9)}`,type:"company",country:"PT"}}},getEntityType:function(t){return{1:"personal",2:"personal",3:"personal",5:"public_entity",6:"non_profit",7:"other_entity",8:"other_entity",9:"other_entity"}[t]||"unknown"}};e.registerRules("pt",o),"undefined"!=typeof window&&window.TaxDocumentValidator&&window.TaxDocumentValidator.registerRules("pt",o)
/**
* USARules - American tax document validation rules
* Provides validation algorithms for SSN and EIN with correct format validation
* @version 1.0.0
* @license MIT
* @author Roni Sommerfeld
* @module USARules
* @requires ValidatorInstance
*/;const i={ssn:function(t){if(9!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"SSN must contain exactly 9 digits",details:{length:t.length,expected:9}};if(/^(\d)\1{8}$/.test(t))return{isValid:!1,error:"SSN cannot have all digits the same",details:{pattern:"repeated_digits"}};const e=t.slice(0,3),n=t.slice(3,5),o=t.slice(5,9);return"000"===e?{isValid:!1,error:"SSN area cannot be 000",details:{area:e,issue:"invalid_area_000"}}:"666"===e?{isValid:!1,error:"",details:{area:e,issue:"invalid_area_666"}}:"9"===e.charAt(0)?{isValid:!1,error:"SSN area cannot start with 9",details:{area:e,issue:"invalid_area_starts_with_9"}}:"00"===n?{isValid:!1,error:"SSN group cannot be 00",details:{group:n,issue:"invalid_group_00"}}:"0000"===o?{isValid:!1,error:"SSN serial number cannot be 0000",details:{serial:o,issue:"invalid_serial_0000"}}:{isValid:!0,error:null,details:{formatted:`${e}-${n}-${o}`,type:"personal",country:"US",parts:{area:e,group:n,serial:o}}}},ein:function(t){if(9!==(t=t.replace(/\D/g,"")).length)return{isValid:!1,error:"EIN must contain exactly 9 digits",details:{length:t.length,expected:9}};if(/^(\d)\1{8}$/.test(t))return{isValid:!1,error:"EIN cannot have all digits the same",details:{pattern:"repeated_digits"}};const e=t.slice(0,2),n=t.slice(2,9);return["01","02","03","04","05","06","10","11","12","13","14","15","16","20","21","22","23","24","25","26","27","30","31","32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47","48","50","51","52","53","54","55","56","57","58","59","60","61","62","63","64","65","66","67","68","71","72","73","74","75","76","77","80","81","82","83","84","85","86","87","88","90","91","92","93","94","95","96","98","99"].includes(e)?"0000000"===n?{isValid:!1,error:"EIN suffix cannot be 0000000",details:{suffix:n,issue:"invalid_suffix_all_zeros"}}:{isValid:!0,error:null,details:{formatted:`${e}-${n}`,type:"company",country:"US",parts:{prefix:e,suffix:n}}}:{isValid:!1,error:"Invalid EIN prefix",details:{prefix:e,issue:"invalid_prefix"}}}};e.registerRules("us",i),"undefined"!=typeof window&&window.TaxDocumentValidator&&window.TaxDocumentValidator.registerRules("us",i);var r={br:{name:"Brasil",iso2:"br",flag:"https://flagcdn.com/w20/br.png",documents:{cpf:{length:11,mask:"XXX.XXX.XXX-XX",type:"personal",priority:1},cnpj:{length:14,mask:"XX.XXX.XXX/XXXX-XX",type:"company",priority:2}}},pt:{name:"Portugal",iso2:"pt",flag:"https://flagcdn.com/w20/pt.png",documents:{nif:{length:9,mask:"XXX XXX XXX",type:"personal",priority:1},nipc:{length:9,mask:"XXX XXX XXX",type:"company",priority:2}}},us:{name:"United States",iso2:"us",flag:"https://flagcdn.com/w20/us.png",documents:{ssn:{length:9,mask:"XXX-XX-XXXX",type:"personal",priority:1},ein:{length:9,mask:"XX-XXXXXXX",type:"company",priority:2}}}};class a{constructor(t,e=[]){this.countries=t,this.onlyCountries=e,this.selectedCountry="br",this.domManager=null,this.isDropdownVisible=!1,this.debugMode=!0}setDOMManager(t){this.domManager=t}initialize(t){this.selectedCountry=t,this.populateCountries(),this.updateSelectedCountry(),this.setupEventListeners(),this.debugMode&&(this.onlyCountries.length>0?this.onlyCountries:Object.keys(this.countries),this.domManager)}populateCountries(){const t=this.onlyCountries.length>0?this.onlyCountries:Object.keys(this.countries);this.domManager.populateCountries(t,t=>{this.selectCountry(t)}),setTimeout(()=>{const e=this.domManager.dropdown.querySelectorAll(".tax-document-input__dropdown-item");e.length,0===e.length&&(console.error("ERRO: Dropdown não foi populado!"),Object.keys(this.countries),this.domManager.populateCountries(t,t=>{this.selectCountry(t)}))},200)}updateSelectedCountry(){const t=this.countries[this.selectedCountry];this.domManager.updateSelectedCountry(t)}selectCountry(t){const e=this.selectedCountry;this.selectedCountry=t,this.updateSelectedCountry(),this.hideDropdown(),this.onCountryChange?.(t,e),this.debugMode}setupEventListeners(){if(!this.domManager||!this.domManager.countryButton||!this.domManager.dropdown)return void console.error("DOMManager não está configurado corretamente");this.domManager.countryButton.addEventListener("click",t=>{t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),this.isDropdownVisible,this.domManager.dropdown.style.display,getComputedStyle(this.domManager.dropdown).display,this.toggleDropdown()}),document.addEventListener("click",t=>{if(this.isDropdownVisible){const e=this.domManager.wrapper.contains(t.target),n=this.domManager.dropdown.contains(t.target);e||n||(this.debugMode&&t.target,this.hideDropdown())}}),this.domManager.dropdown.addEventListener("click",t=>{t.stopPropagation(),t.stopImmediatePropagation(),this.debugMode&&t.target});const t=()=>{this.isDropdownVisible&&this.positionDropdown()};window.addEventListener("resize",t),window.addEventListener("scroll",t,!0),document.addEventListener("keydown",t=>{"Escape"===t.key&&this.isDropdownVisible&&this.hideDropdown()}),this.debugMode}toggleDropdown(){this.domManager&&this.domManager.dropdown?(this.isDropdownVisible,this.isDropdownVisible?this.hideDropdown():this.showDropdown()):console.error("Dropdown não encontrado")}showDropdown(){if(this.domManager&&this.domManager.dropdown)try{this.positionDropdown(),this.domManager.forceShowDropdown(),this.domManager.dropdown.setAttribute("data-visible","true"),this.domManager.dropdown.style.display="block",this.domManager.dropdown.style.visibility="visible",this.domManager.dropdown.style.opacity="1",this.domManager.dropdown.offsetHeight,this.domManager.dropdown.getBoundingClientRect(),this.isDropdownVisible=!0,requestAnimationFrame(()=>{const t=this.domManager.dropdown.getBoundingClientRect(),e=getComputedStyle(this.domManager.dropdown);e.display,e.position,e.top,e.left,e.zIndex,e.visibility,e.opacity,t.width,t.height,this.isInViewport(t),this.domManager.dropdown.children.length,this.domManager.dropdown.style.display,this.domManager.dropdown.getAttribute("data-visible");"none"===e.display||0===t.width?(console.warn("Dropdown ainda não visível, aplicando correção de emergência"),this.emergencyShowFix()):this.highlightDropdown()})}catch(t){console.error("Erro em showDropdown:",t),this.emergencyShowFix()}else console.error("Elementos necessários não encontrados para showDropdown")}emergencyShowFix(){const t=document.createElement("div");t.id="emergency-dropdown-"+Date.now(),t.innerHTML=this.domManager.dropdown.innerHTML,Object.assign(t.style,{position:"fixed",top:"100px",left:"100px",width:"250px",maxHeight:"200px",backgroundColor:"#ffcccc",border:"3px solid red",zIndex:"2147483647",padding:"10px",borderRadius:"4px",boxShadow:"0 4px 20px rgba(0,0,0,0.5)",fontSize:"14px",fontFamily:"Arial, sans-serif",overflowY:"auto"});const e=document.createElement("div");e.style.cssText="background: yellow; padding: 5px; margin-bottom: 5px; font-size: 12px;",e.textContent="DROPDOWN DE EMERGÊNCIA - Há conflito de CSS!",t.insertBefore(e,t.firstChild),document.body.appendChild(t),setTimeout(()=>{document.body.contains(t)&&document.body.removeChild(t)},5e3)}highlightDropdown(){const t=this.domManager.dropdown.style.backgroundColor,e=this.domManager.dropdown.style.border;this.domManager.dropdown.style.backgroundColor="#ffffcc",this.domManager.dropdown.style.border="3px solid green",setTimeout(()=>{this.domManager.dropdown.style.backgroundColor=t||"white",this.domManager.dropdown.style.border=e||"1px solid #ccc"},1500)}hideDropdown(){this.domManager&&this.domManager.dropdown&&(this.domManager.dropdown.style.display="none",this.domManager.dropdown.removeAttribute("data-visible"),this.isDropdownVisible=!1,this.debugMode)}positionDropdown(){if(!this.domManager.countryContainer)return void console.error("countryContainer não encontrado para posicionamento");const t=this.domManager.countryContainer.getBoundingClientRect(),e=window.innerHeight,n=window.innerWidth;this.debugMode;let o=t.bottom+5,i=t.left;const r=Math.max(t.width,200),a=e-t.bottom,s=Math.min(250,this.domManager.dropdown.scrollHeight||200);this.debugMode,a<s&&t.top>s&&(o=t.top-s-5,this.debugMode),i+r>n&&(i=n-r-20,this.debugMode),i<20&&(i=20),o<20&&(o=20),o+s>e&&(o=e-s-20),this.debugMode,Object.assign(this.domManager.dropdown.style,{top:`${o}px`,left:`${i}px`,width:`${r}px`,maxHeight:`${s}px`})}isInViewport(t){return t.top>=0&&t.left>=0&&t.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&t.right<=(window.innerWidth||document.documentElement.clientWidth)}debugCurrentState(){this.selectedCountry,this.isDropdownVisible,this.domManager,this.domManager,this.domManager?.dropdown&&this.domManager.debugDropdown()}autoGeolocate(t){t.autoGeolocate&&(t.geoIpLookup&&"function"==typeof t.geoIpLookup?t.geoIpLookup(t=>{t&&this.countries[t.toLowerCase()]&&this.selectCountry(t.toLowerCase())}):this.defaultGeoIpLookup(t=>{t&&this.countries[t.toLowerCase()]&&this.selectCountry(t.toLowerCase())}))}defaultGeoIpLookup(t){fetch("https://ipapi.co/json").then(t=>t.json()).then(e=>{e.country_code,t(e.country_code)}).catch(e=>{t("br")})}getSelectedCountry(){return this.selectedCountry}getSelectedCountryData(){return this.countries[this.selectedCountry]}setDebugMode(t){this.debugMode=t}onCountryChange=null}class s{constructor(t,e){this.input=t,this.countries=e,this.wrapper=null,this.countryContainer=null,this.countryButton=null,this.dropdown=null,this.uniqueId="tax-dropdown-"+Math.random().toString(36).substr(2,9)}createWrapper(){this.wrapper=document.createElement("div"),this.wrapper.className="tax-document-input",this.input.parentNode.insertBefore(this.wrapper,this.input),this.wrapper.appendChild(this.input),this.input.className+=" tax-document-input__field",this.addStyles()}createCountrySelector(){this.countryContainer=document.createElement("div"),this.countryContainer.className="tax-document-input__country",this.countryButton=document.createElement("button"),this.countryButton.type="button",this.countryButton.className="tax-document-input__country-button",this.dropdown=document.createElement("ul"),this.dropdown.className="tax-document-input__dropdown",this.dropdown.id=this.uniqueId,this.dropdown.setAttribute("data-tax-dropdown","true"),this.applyInlineStyles(),this.countryContainer.appendChild(this.countryButton),document.body.appendChild(this.dropdown),this.wrapper.insertBefore(this.countryContainer,this.input),this.uniqueId}applyInlineStyles(){Object.assign(this.dropdown.style,{position:"fixed",zIndex:"2147483647",margin:"0",padding:"0",listStyle:"none",display:"none",backgroundColor:"white",border:"1px solid #ccc",borderRadius:"4px",boxShadow:"0 4px 12px rgba(0,0,0,0.15)",maxHeight:"200px",overflowY:"auto",minWidth:"150px",opacity:"1",visibility:"visible",pointerEvents:"auto",fontSize:"14px",fontFamily:"Arial, sans-serif",boxSizing:"border-box"})}forceShowDropdown(){let t="";Object.entries({display:"block !important",position:"fixed !important",zIndex:"2147483647 !important",backgroundColor:"white !important",border:"2px solid #007bff !important",visibility:"visible !important",opacity:"1 !important",pointerEvents:"auto !important"}).forEach(([e,n])=>{const o=e.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`);t+=`${o}: ${n}; `}),this.dropdown.style.cssText+=t}populateCountries(t,e){this.dropdown.innerHTML="",t.forEach(t=>{if(this.countries[t]){const n=this.countries[t];n.name;const o=document.createElement("li");o.className="tax-document-input__dropdown-item",o.setAttribute("data-country",t),Object.assign(o.style,{padding:"8px 12px",cursor:"pointer",display:"flex",alignItems:"center",gap:"8px",backgroundColor:"white",borderBottom:"1px solid #eee",fontSize:"14px",color:"#333",boxSizing:"border-box"}),o.innerHTML=`\n <img src="${n.flag}" alt="${n.name}"\n style="width: 20px; height: 15px; object-fit: cover; border-radius: 2px;" />\n <span style="font-size: 14px; color: #333;">${n.name}</span>\n `,o.addEventListener("click",n=>{n.preventDefault(),n.stopPropagation(),n.stopImmediatePropagation(),e&&e(t)}),o.addEventListener("mouseenter",()=>{o.style.backgroundColor="#f5f5f5"}),o.addEventListener("mouseleave",()=>{o.style.backgroundColor="white"}),this.dropdown.appendChild(o)}}),this.dropdown.children.length}updateSelectedCountry(t){t&&(this.countryButton.innerHTML=`\n <img src="${t.flag}" alt="${t.name}"\n style="width: 20px; height: 15px; object-fit: cover; border-radius: 2px;" />\n <span style="font-size: 10px; color: #666;">▼</span>\n `)}setValidationState(t){this.input.classList.remove("tax-document-input--valid","tax-document-input--invalid"),!0===t?this.input.classList.add("tax-document-input--valid"):!1===t&&this.input.classList.add("tax-document-input--invalid")}destroy(){this.dropdown&&document.body.contains(this.dropdown)&&document.body.removeChild(this.dropdown),this.wrapper&&this.wrapper.parentNode&&(this.wrapper.parentNode.insertBefore(this.input,this.wrapper),this.wrapper.remove()),this.input.className=this.input.className.replace("tax-document-input__field",""),this.input.classList.remove("tax-document-input--valid","tax-document-input--invalid")}addStyles(){if(document.getElementById("tax-document-input-styles"))return;const t=document.createElement("style");t.id="tax-document-input-styles",t.textContent='\n /* Reset e estilos base */\n .tax-document-input {\n width: 100% !important;\n position: relative !important;\n display: inline-flex !important;\n align-items: center !important;\n border: 1px solid #ccc !important;\n border-radius: 4px !important;\n background: white !important;\n font-family: Arial, sans-serif !important;\n box-sizing: border-box !important;\n }\n\n .tax-document-input__country {\n position: relative !important;\n display: inline-block !important;\n }\n\n .tax-document-input__country-button {\n background: none !important;\n border: none !important;\n padding: 8px 12px !important;\n cursor: pointer !important;\n display: flex !important;\n align-items: center !important;\n gap: 5px !important;\n border-right: 1px solid #eee !important;\n box-sizing: border-box !important;\n font-family: inherit !important;\n font-size: 14px !important;\n }\n\n .tax-document-input__country-button:hover {\n background-color: #f5f5f5 !important;\n }\n\n .tax-document-input__field {\n border: none !important;\n outline: none !important;\n padding: 8px 12px !important;\n font-size: 14px !important;\n flex: 1 !important;\n min-width: 200px !important;\n transition: border-color 0.2s ease !important;\n box-sizing: border-box !important;\n font-family: inherit !important;\n background: transparent !important;\n }\n\n .tax-document-input__field:focus {\n outline: none !important;\n box-shadow: none !important;\n }\n\n /* Estados de validação */\n .tax-document-input--valid {\n border-color: #28a745 !important;\n box-shadow: 0 0 0 2px rgba(40, 167, 69, 0.2) !important;\n }\n\n .tax-document-input--invalid {\n border-color: #dc3545 !important;\n box-shadow: 0 0 0 2px rgba(220, 53, 69, 0.2) !important;\n }\n\n /* Dropdown - Máxima especificidade */\n ul.tax-document-input__dropdown[data-tax-dropdown="true"] {\n position: fixed !important;\n background: white !important;\n border: 1px solid #ccc !important;\n border-radius: 4px !important;\n max-height: 200px !important;\n overflow-y: auto !important;\n z-index: 2147483647 !important;\n margin: 0 !important;\n padding: 0 !important;\n list-style: none !important;\n box-shadow: 0 4px 12px rgba(0,0,0,0.15) !important;\n min-width: 150px !important;\n opacity: 1 !important;\n visibility: visible !important;\n pointer-events: auto !important;\n font-family: Arial, sans-serif !important;\n font-size: 14px !important;\n box-sizing: border-box !important;\n display: none !important;\n }\n\n /* Quando visível - usar atributo para maior especificidade */\n ul.tax-document-input__dropdown[data-tax-dropdown="true"][data-visible="true"] {\n display: block !important;\n }\n\n /* Items do dropdown */\n ul.tax-document-input__dropdown[data-tax-dropdown="true"] > li.tax-document-input__dropdown-item {\n padding: 8px 12px !important;\n cursor: pointer !important;\n display: flex !important;\n align-items: center !important;\n gap: 8px !important;\n background: white !important;\n border-bottom: 1px solid #eee !important;\n font-size: 14px !important;\n color: #333 !important;\n box-sizing: border-box !important;\n list-style: none !important;\n margin: 0 !important;\n }\n\n ul.tax-document-input__dropdown[data-tax-dropdown="true"] > li.tax-document-input__dropdown-item:hover {\n background-color: #f5f5f5 !important;\n }\n\n ul.tax-document-input__dropdown[data-tax-dropdown="true"] > li.tax-document-input__dropdown-item:last-child {\n border-bottom: none !important;\n }\n\n /* Reset de possíveis conflitos */\n .tax-document-input *,\n .tax-document-input *::before,\n .tax-document-input *::after {\n box-sizing: border-box !important;\n }\n\n /* Sobrescrever Bootstrap, Tailwind, etc. */\n .tax-document-input .dropdown,\n .tax-document-input .dropdown-menu,\n .tax-document-input .dropdown-item {\n position: static !important;\n display: block !important;\n border: none !important;\n margin: 0 !important;\n padding: 8px 12px !important;\n background: transparent !important;\n box-shadow: none !important;\n transform: none !important;\n }\n ',document.head.appendChild(t)}debugDropdown(){if(this.dropdown,document.body.contains(this.dropdown),this.dropdown,this.dropdown,this.dropdown){const t=getComputedStyle(this.dropdown);this.dropdown.getBoundingClientRect(),t.display,t.position,t.zIndex,t.visibility,t.opacity,t.top,t.left,t.width,t.height,this.dropdown.style.cssText;const e=[];for(let t of document.styleSheets)try{for(let n of t.cssRules||t.rules)n.selectorText&&n.selectorText.includes("dropdown")&&e.push(n.cssText)}catch(t){}e.length}}}class d{constructor(t,e){this.input=t,this.countries=e,this.selectedCountry="br",this.currentDocument=null}detectDocumentType(){const t=this.input.value.replace(/\D/g,""),e=this.countries[this.selectedCountry];if(!e)return;const n=Object.entries(e.documents).sort((t,e)=>t[1].priority-e[1].priority);if(0!==t.length){for(const[e,o]of n)if(t.length<=o.length)return void(this.currentDocument=e);this.currentDocument=n[n.length-1][0]}else this.currentDocument=n[0][0]}getMaxLength(){const t=this.countries[this.selectedCountry];return t?Math.max(...Object.values(t.documents).map(t=>t.length)):0}formatInput(t){const e=t.target,n=e.selectionStart;let o=e.value.replace(/\D/g,"");const i=this.countries[this.selectedCountry];if(!i)return;const r=this.getMaxLength();o=o.substring(0,r),this.detectDocumentType();const a=i.documents[this.currentDocument];if(!a)return;const s=this.applyMask(o,a.mask),d=this.calculateCursorPosition(e.value,s,n);e.value=s,setTimeout(()=>{e.setSelectionRange(d,d)},0),this.onFormatChange?.(o,this.currentDocument)}applyMask(t,e){let n="",o=0;for(let i=0;i<e.length&&o<t.length;i++)"X"===e[i]?(n+=t[o],o++):n+=e[i];return n}calculateCursorPosition(t,e,n){let o=0;for(let e=0;e<n&&e<t.length;e++)/\d/.test(t[e])&&o++;let i=0,r=0;for(let t=0;t<e.length&&!(/\d/.test(e[t])&&(r++,r>o));t++)i=t+1;return i}setSelectedCountry(t){this.selectedCountry=t,this.currentDocument=null,this.detectDocumentType()}getCurrentDocumentInfo(){const t=this.countries[this.selectedCountry];if(!t||!this.currentDocument)return null;const e=t.documents[this.currentDocument];return{type:this.currentDocument,category:e.type,length:e.length,mask:e.mask,country:this.selectedCountry}}getCleanValue(){return this.input.value.replace(/\D/g,"")}getFormattedValue(){return this.input.value}clear(){this.input.value="",this.currentDocument=null,this.detectDocumentType()}onFormatChange=null}class l{constructor(){this.validator=e,this.lastValidationResult=null}validateDocument(t,e,n){if(!e||!n)return{isValid:!1,error:"País ou tipo de documento não definido",details:null};const o=this.validator.validate(t,e,n);return this.lastValidationResult={...o,documentType:n,country:e},this.lastValidationResult}validateLength(t,e){return t&&e?0===t.length?null:!(t.length<e)&&t.length===e:null}isDocumentValid(t,e,n,o){if(t.length!==o)return!1;return this.validateDocument(t,e,n).isValid}getValidationState(t,e,n,o){if(!t||0===t.length)return null;if(t.length<o)return null;if(t.length===o){return this.validateDocument(t,e,n).isValid}return!1}getLastValidationResult(){return this.lastValidationResult}getValidationError(t,e,n){return this.validateDocument(t,e,n).error}hasRulesForCountry(t){return this.validator.hasRules(t)}getSupportedDocuments(t){return this.validator.getSupportedDocuments(t)}clearValidationCache(){this.lastValidationResult=null}}
/**
* TaxDocumentInput - Plugin to handle tax document inputs
* This plugin provides a unified interface for handling tax document inputs across multiple countries,
* including formatting, validation, and country selection.
* @version 1.0.0
* @license MIT
* @author Roni Sommerfeld
* @module TaxDocumentInput
* @requires CountriesData
* @requires CountryManager
* @requires DOMManager
* @requires FormatManager
*/class u{constructor(t,e={}){this.input=t,this.options={placeholder:"Document Tax",defaultCountry:"br",autoGeolocate:!1,onlyCountries:[],geoIpLookup:null,...e},this.countries=r,this.domManager=new s(this.input,this.countries),this.formatManager=new d(this.input,this.countries),this.countryManager=new a(this.countries,this.options.onlyCountries),this.validationManager=new l,this.isInitialized=!1,this.init()}init(){if(!this.isInitialized)try{this.domManager.createWrapper(),this.domManager.createCountrySelector(),this.countryManager.setDOMManager(this.domManager),this.formatManager.setSelectedCountry(this.options.defaultCountry),this.setupCallbacks(),this.countryManager.initialize(this.options.defaultCountry),this.setupEventListeners(),this.updatePlaceholder(),this.options.autoGeolocate&&this.countryManager.autoGeolocate(this.options),this.isInitialized=!0}catch(t){console.error("Erro ao inicializar TaxDocumentInput:",t)}}setupCallbacks(){this.countryManager.onCountryChange=(t,e)=>{this.formatManager.setSelectedCountry(t),this.formatManager.clear(),this.validationManager.clearValidationCache(),this.domManager.setValidationState(null);const n=new CustomEvent("countrychange",{detail:{previousCountry:e,newCountry:t,countryData:this.countries[t]}});this.input.dispatchEvent(n)},this.formatManager.onFormatChange=(t,e)=>{this.updateValidationState(t,e)}}setupEventListeners(){this.input.addEventListener("input",t=>{this.formatManager.formatInput(t)}),this.input.addEventListener("focus",()=>{this.input.classList.add("tax-document-input--focused")}),this.input.addEventListener("blur",()=>{this.input.classList.remove("tax-document-input--focused");this.formatManager.getCleanValue().length>0&&this.triggerCompleteValidation()})}updateValidationState(t,e){if(!e)return;const n=this.countryManager.getSelectedCountry(),o=this.countries[n]?.documents[e];if(!o)return;const i=this.validationManager.getValidationState(t,n,e,o.length);this.domManager.setValidationState(i)}triggerCompleteValidation(){const t=this.formatManager.getCleanValue(),e=this.formatManager.currentDocument,n=this.countryManager.getSelectedCountry();if(t&&e&&n){const o=this.validationManager.validateDocument(t,n,e);this.domManager.setValidationState(o.isValid);const i=new CustomEvent("validation",{detail:o});this.input.dispatchEvent(i)}}updatePlaceholder(){this.input.placeholder=this.options.placeholder}getSelectedCountry(){return this.countryManager.getSelectedCountry()}getSelectedCountryData(){return this.countryManager.getSelectedCountryData()}getCurrentDocumentType(){return this.formatManager.currentDocument}getCurrentDocumentInfo(){return this.formatManager.getCurrentDocumentInfo()}setCountry(t){this.countries[t]&&this.countryManager.selectCountry(t)}getValue(){return this.formatManager.getFormattedValue()}getCleanValue(){return this.formatManager.getCleanValue()}setValue(t){this.input.value=t;const e=new Event("input",{bubbles:!0});this.input.dispatchEvent(e)}clear(){this.formatManager.clear(),this.validationManager.clearValidationCache(),this.domManager.setValidationState(null)}isValid(){const t=this.getCleanValue(),e=this.getSelectedCountry(),n=this.getCurrentDocumentType(),o=this.getCurrentDocumentInfo();return!!(o&&n&&e)&&this.validationManager.isDocumentValid(t,e,n,o.length)}validateDocument(){const t=this.getCleanValue(),e=this.getSelectedCountry(),n=this.getCurrentDocumentType(),o=this.getCurrentDocumentInfo();if(!o||!n||!e)return{isValid:!1,error:"País ou tipo de documento não definido",details:null,documentType:null,documentCategory:null,country:null};if(t.length!==o.length)return{isValid:!1,error:`Documento deve ter ${o.length} dígitos`,details:{currentLength:t.length,expectedLength:o.length},documentType:n,documentCategory:o.category,country:e};return{...this.validationManager.validateDocument(t,e,n),documentType:n,documentCategory:o.category,country:e}}revalidate(){this.validationManager.clearValidationCache(),this.triggerCompleteValidation()}hasValidationRules(){const t=this.getSelectedCountry();return this.validationManager.hasRulesForCountry(t)}getSupportedDocuments(){const t=this.getSelectedCountry();return this.validationManager.getSupportedDocuments(t)}setEnabled(t){this.input.disabled=!t,this.domManager.countryButton.disabled=!t,t?this.input.classList.remove("tax-document-input--disabled"):this.input.classList.add("tax-document-input--disabled")}isEnabled(){return!this.input.disabled}focus(){this.input.focus()}getStats(){return{country:this.getSelectedCountry(),documentType:this.getCurrentDocumentType(),isValid:this.isValid(),valueLength:this.getCleanValue().length,hasValidationRules:this.hasValidationRules(),isEnabled:this.isEnabled(),lastValidation:this.validationManager.getLastValidationResult()}}updateOptions(t){this.options={...this.options,...t},t.placeholder&&this.updatePlaceholder(),t.defaultCountry&&this.countries[t.defaultCountry]&&this.setCountry(t.defaultCountry),t.onlyCountries&&(this.countryManager.onlyCountries=t.onlyCountries,this.countryManager.populateCountries())}destroy(){this.isInitialized&&(this.input.removeEventListener("input",this.formatManager.formatInput),this.domManager.destroy(),this.domManager=null,this.formatManager=null,this.countryManager=null,this.validationManager=null,this.isInitialized=!1)}static create(t,e={}){const n="string"==typeof t?document.querySelector(t):t;if(!n)throw new Error("Elemento não encontrado");return new u(n,e)}static init(t,e={}){const n=document.querySelectorAll(t),o=[];return n.forEach(t=>{o.push(new u(t,e))}),1===o.length?o[0]:o}static get version(){return"2.0.0"}static getSupportedCountries(){return["br","pt","us"]}}function c(t,e={}){const n=document.querySelectorAll(t),o=[];return n.forEach(t=>{o.push(new u(t,e))}),1===o.length?o[0]:o}"undefined"!=typeof window&&(window.TaxDocumentInput=u,u.init=function(t,e){return u.init(t,e)}),"undefined"!=typeof window&&(window.TaxDocumentInput=u,window.TaxDocumentValidator=e,window.initTaxInputs=c),t.CountryManager=a,t.DOMManager=s,t.FormatManager=d,t.TaxDocumentInput=u,t.ValidationManager=l,t.Validator=e,t.default=u,t.initTaxInputs=c,Object.defineProperty(t,"__esModule",{value:!0})});