@anilkumarthakur/vue3-recaptcha
Version:
A Vue 3 plugin for Google reCAPTCHA v2 (checkbox & invisible) and v3 integration
3 lines (2 loc) • 11.6 kB
JavaScript
var Vue3Recaptcha=(function(y,r){Object.defineProperties(y,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var I=Symbol("vue3-recaptcha"),L="vue3-recaptcha-script",W="https://www.google.com/recaptcha/api.js",C=null,k=!1;function S(){return k&&typeof window<"u"&&typeof window.grecaptcha<"u"}function _(){return document.querySelector(`#${L}`)}function H(){const e=_();e&&e.remove(),C=null,k=!1}function N(e){const{siteKey:t,version:d,language:c,scriptUrl:n}=e;if(n)return n;const o=new URLSearchParams;return d==="v3"?o.set("render",t):(o.set("render","explicit"),typeof window<"u"&&(window.___grecaptcha_cfg=window.___grecaptcha_cfg??{},window.___grecaptcha_cfg.explicit=!0)),c&&o.set("hl",c),`${W}?${o.toString()}`}function T(e){return C||(S()?Promise.resolve():(C=new Promise((t,d)=>{const c=_();if(c){if(S()){t();return}c.addEventListener("load",()=>{k=!0,e.onLoad?.(),t()}),c.addEventListener("error",()=>{const o=new Error("Failed to load reCAPTCHA script");e.onError?.(o),d(o)});return}const n=document.createElement("script");n.id=L,n.src=N(e),n.async=!0,n.defer=!0,n.onload=()=>{e.version==="v3"?window.grecaptcha.ready(()=>{k=!0,e.onLoad?.(),t()}):(k=!0,e.onLoad?.(),t())},n.onerror=()=>{const o=new Error("Failed to load reCAPTCHA script");C=null,e.onError?.(o),d(o)},document.head.appendChild(n)}),C))}function U(){return new Promise((e,t)=>{if(S()){e();return}const d=window.setTimeout(()=>{window.clearInterval(c),t(new Error("Timeout waiting for reCAPTCHA to load"))},1e4),c=window.setInterval(()=>{typeof window.grecaptcha<"u"&&(window.clearInterval(c),window.clearTimeout(d),typeof window.grecaptcha.ready=="function"?window.grecaptcha.ready(()=>{k=!0,e()}):(k=!0,e()))},100)})}var K=(0,r.defineComponent)({name:"RecaptchaV2Checkbox",props:{siteKey:{type:String,default:void 0},theme:{type:String,default:"light"},size:{type:String,default:"normal"},tabindex:{type:Number,default:0},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",expire:null,error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(null),n=(0,r.ref)(null),o=(0,r.ref)(!1),l=(0,r.inject)(I,void 0),i=(0,r.computed)(()=>e.siteKey??l?.siteKey??"");i.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV2Checkbox");function s(a){t("update:modelValue",a),t("verify",a)}function E(){t("update:modelValue",""),t("expire")}function m(a){t("update:modelValue",""),t("error",a)}async function h(){const a=c.value,v=i.value;if(!(!a||!v))try{S()||await T({siteKey:v,version:"v2"}),await new Promise(g=>{const u=window.setInterval(()=>{typeof window.grecaptcha?.render=="function"&&(window.clearInterval(u),g())},50)}),n.value=window.grecaptcha.render(a,{sitekey:v,theme:e.theme,size:e.size,tabindex:e.tabindex,callback:s,"expired-callback":E,"error-callback":()=>{m(new Error("reCAPTCHA verification error"))}}),o.value=!0,t("load")}catch(g){m(g instanceof Error?g:new Error(String(g)))}}function f(){const a=n.value;a!==null&&(window.grecaptcha.reset(a),t("update:modelValue",""))}function p(){const a=n.value;return a!==null?window.grecaptcha.getResponse(a):""}return(0,r.watch)(()=>[e.theme,e.size],()=>{const a=c.value;o.value&&a&&(a.innerHTML="",n.value=null,o.value=!1,h())}),(0,r.onMounted)(()=>{h()}),(0,r.onBeforeUnmount)(()=>{n.value=null}),d({reset:f,getResponse:p,widgetId:n}),()=>(0,r.createVNode)("div",{ref:c,class:"vue3-recaptcha-v2-checkbox",style:{display:"inline-block"}},null)}}),A=(0,r.defineComponent)({name:"RecaptchaV2Invisible",props:{siteKey:{type:String,default:void 0},badge:{type:String,default:"bottomright"},tabindex:{type:Number,default:0},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",expire:null,error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(null),n=(0,r.ref)(null),o=(0,r.ref)(!1),l=(0,r.ref)(null),i=(0,r.ref)(null),s=(0,r.inject)(I,void 0),E=(0,r.computed)(()=>e.siteKey??s?.siteKey??"");E.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV2Invisible");function m(u){t("update:modelValue",u),t("verify",u);const w=l.value;w&&(l.value=null,i.value=null,w(u))}function h(){t("update:modelValue",""),t("expire")}function f(u){t("update:modelValue",""),t("error",u);const w=i.value;w&&(l.value=null,i.value=null,w(u))}async function p(){const u=c.value,w=E.value;if(!(!u||!w))try{S()||await T({siteKey:w,version:"v2"}),await new Promise(R=>{const b=window.setInterval(()=>{typeof window.grecaptcha?.render=="function"&&(window.clearInterval(b),R())},50)}),n.value=window.grecaptcha.render(u,{sitekey:w,size:"invisible",tabindex:e.tabindex,callback:m,"expired-callback":h,"error-callback":()=>{f(new Error("reCAPTCHA verification error"))}}),o.value=!0,t("load")}catch(R){f(R instanceof Error?R:new Error(String(R)))}}async function a(){o.value||await p();const u=n.value;if(u===null)throw new Error("[vue3-recaptcha] Widget not initialized");return new Promise((w,R)=>{const b=window.setTimeout(()=>{const V=i.value;l.value=null,i.value=null,V?.(new Error("[vue3-recaptcha] Verification timeout after 60 seconds"))},6e4);l.value=V=>{window.clearTimeout(b),w(V)},i.value=V=>{window.clearTimeout(b),R(V)};try{window.grecaptcha.execute(u)}catch(V){window.clearTimeout(b),l.value=null,i.value=null,R(V instanceof Error?V:new Error(String(V)))}})}function v(){const u=n.value;u!==null&&(window.grecaptcha.reset(u),t("update:modelValue",""),l.value=null,i.value=null)}function g(){const u=n.value;return u!==null?window.grecaptcha.getResponse(u):""}return(0,r.onMounted)(()=>{p()}),(0,r.onBeforeUnmount)(()=>{n.value=null,l.value=null,i.value=null}),d({execute:a,reset:v,getResponse:g,widgetId:n}),()=>(0,r.createVNode)("div",{ref:c,class:"vue3-recaptcha-v2-invisible",style:{display:"none"}},null)}}),x=(0,r.defineComponent)({name:"RecaptchaV3",props:{siteKey:{type:String,default:void 0},action:{type:String,default:"submit"},badge:{type:String,default:"bottomright"},hideBadge:{type:Boolean,default:!1},modelValue:{type:String,default:""}},emits:{"update:modelValue":e=>typeof e=="string",verify:e=>typeof e=="string",error:e=>e instanceof Error,load:null},setup(e,{emit:t,expose:d}){const c=(0,r.ref)(!1),n=(0,r.ref)(!1),o=(0,r.ref)(null);let l;const i=(0,r.inject)(I,void 0),s=(0,r.computed)(()=>e.siteKey??i?.siteKey??"");s.value||console.error("[vue3-recaptcha] Site key is required for RecaptchaV3");function E(){if(typeof document>"u")return;const f=document.querySelector(".grecaptcha-badge");f&&(f.style.visibility=e.hideBadge?"hidden":"visible")}async function m(){if(!(c.value||n.value)){n.value=!0,o.value=null;try{await T({siteKey:s.value,version:"v3",onLoad:()=>{c.value=!0,t("load")},onError:f=>{o.value=f,t("error",f)}}),c.value=!0}catch(f){const p=f instanceof Error?f:new Error(String(f));o.value=p,t("error",p)}finally{n.value=!1}}}async function h(f){if(c.value||await m(),typeof window.grecaptcha>"u"){const v=new Error("[vue3-recaptcha] grecaptcha is not available");throw t("error",v),v}const p=s.value,a=f??e.action??"submit";try{const v=await window.grecaptcha.execute(p,{action:a});return t("update:modelValue",v),t("verify",v),l!==void 0&&clearTimeout(l),l=setTimeout(()=>{t("update:modelValue","")},11e4),v}catch(v){const g=v instanceof Error?v:new Error(String(v));throw o.value=g,t("error",g),t("update:modelValue",""),g}}return(0,r.watch)(()=>e.hideBadge,E),(0,r.onMounted)(()=>{m().then(()=>{E()})}),(0,r.onBeforeUnmount)(()=>{l!==void 0&&clearTimeout(l)}),d({load:m,loadRecaptcha:m,execute:h,isLoaded:c,isLoading:n,error:o}),()=>(0,r.createVNode)("div",{class:"vue3-recaptcha-v3",style:{display:"none"}},null)}});function q(e={}){const t=(0,r.inject)(I,void 0),d=e.siteKey??t?.siteKey;if(!d)throw new Error("[vue3-recaptcha] Site key is required. Provide it via plugin options or composable options.");const c=d,n=(0,r.ref)(""),o=(0,r.ref)(!1),l=(0,r.ref)(!1),i=(0,r.ref)(null),s=(0,r.ref)(null);async function E(){if(S()){o.value=!0;return}l.value=!0,i.value=null;try{await T({siteKey:c,version:"v2",onError:a=>{i.value=a}}),o.value=!0}catch(a){throw i.value=a instanceof Error?a:new Error(String(a)),i.value}finally{l.value=!1}}async function m(a){return await E(),s.value!==null&&f(),new Promise((v,g)=>{try{const u=window.grecaptcha.render(a,{sitekey:c,theme:e.theme,size:e.size,tabindex:e.tabindex,callback:w=>{n.value=w},"expired-callback":()=>{n.value=""},"error-callback":()=>{i.value=new Error("reCAPTCHA verification error"),n.value=""}});s.value=u,v(u)}catch(u){const w=u instanceof Error?u:new Error(String(u));i.value=w,g(w)}})}async function h(){await E();const a=s.value;if(a===null)throw new Error("[vue3-recaptcha] Widget not rendered. Call render() first.");return new Promise((v,g)=>{const u=n.value,w=setInterval(()=>{n.value&&n.value!==u&&(clearInterval(w),clearTimeout(R),v(n.value))},100),R=setTimeout(()=>{clearInterval(w),g(new Error("[vue3-recaptcha] Execute timeout after 30 seconds"))},3e4);try{window.grecaptcha.execute(a)}catch(b){clearInterval(w),clearTimeout(R),g(b instanceof Error?b:new Error(String(b)))}})}function f(){const a=s.value;a!==null&&(window.grecaptcha.reset(a),n.value="")}function p(){const a=s.value;return a!==null?window.grecaptcha.getResponse(a):n.value}return(0,r.onUnmounted)(()=>{s.value=null,n.value=""}),{token:(0,r.readonly)(n),isReady:(0,r.readonly)(o),isLoading:(0,r.readonly)(l),error:(0,r.readonly)(i),widgetId:(0,r.readonly)(s),render:m,execute:h,reset:f,getResponse:p}}function z(e={}){const t=(0,r.inject)(I,void 0),d=e.siteKey??t?.siteKey;if(!d)throw new Error("[vue3-recaptcha] Site key is required. Provide it via plugin options or composable options.");const c=d,n=(0,r.ref)(""),o=(0,r.ref)(!1),l=(0,r.ref)(!1),i=(0,r.ref)(null);let s;async function E(){if(S()){o.value=!0;return}l.value=!0,i.value=null;try{await T({siteKey:c,version:"v3",onError:h=>{i.value=h}}),o.value=!0}catch(h){throw i.value=h instanceof Error?h:new Error(String(h)),i.value}finally{l.value=!1}}async function m(h){await E();const f=h??e.action??"submit";l.value=!0,i.value=null;try{const p=await window.grecaptcha.execute(c,{action:f});return n.value=p,s!==void 0&&clearTimeout(s),s=setTimeout(()=>{n.value=""},11e4),p}catch(p){const a=p instanceof Error?p:new Error(String(p));throw i.value=a,n.value="",a}finally{l.value=!1}}return(0,r.onUnmounted)(()=>{s!==void 0&&clearTimeout(s),n.value=""}),{token:(0,r.readonly)(n),isReady:(0,r.readonly)(o),isLoading:(0,r.readonly)(l),error:(0,r.readonly)(i),execute:m}}var P={install(e,t){if(!t?.siteKey){console.error("[vue3-recaptcha] Site key is required");return}const d=t.version??"v3",c=(0,r.ref)(!1);e.component("RecaptchaV2Checkbox",K),e.component("RecaptchaV2Invisible",A),e.component("RecaptchaV2",K),e.component("RecaptchaV3",x),e.component("Recaptcha",x);const n=async()=>{await T({siteKey:t.siteKey,version:d,language:t.language,scriptUrl:t.scriptUrl,onLoad:()=>{c.value=!0,t.onLoad?.()}}),c.value=!0},o={siteKey:t.siteKey,version:d,isLoaded:c,loadScript:n};e.provide(I,o),t.autoLoad!==!1&&n().catch(l=>{const i=l instanceof Error?l:new Error(String(l));console.error("[vue3-recaptcha] Failed to auto-load script:",i),t.onError?.(i)})}},B=P;return y.RECAPTCHA_INJECTION_KEY=I,y.Recaptcha=x,y.RecaptchaV3=x,y.RecaptchaV2=K,y.RecaptchaV2Checkbox=K,y.RecaptchaV2Invisible=A,y.VueRecaptchaPlugin=P,y.default=P,y.isRecaptchaLoaded=S,y.loadRecaptchaScript=T,y.recaptchaPlugin=B,y.removeScript=H,y.useRecaptchaV2=q,y.useRecaptchaV3=z,y.waitForRecaptcha=U,y})({},Vue);
//# sourceMappingURL=index.iife.js.map