form-father 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/FormFather.min.js CHANGED
@@ -1,2 +1,2 @@
1
- var FormFather=function(t){"use strict";function e(t,e,o,r){return new(o||(o=Promise))((function(i,n){function s(t){try{l(r.next(t))}catch(t){n(t)}}function a(t){try{l(r.throw(t))}catch(t){n(t)}}function l(t){var e;t.done?i(t.value):(e=t.value,e instanceof o?e:new o((function(t){t(e)}))).then(s,a)}l((r=r.apply(t,e||[])).next())}))}function o(t){const e="FORM"===t.tagName?Array.from(t.elements):Array.from(t.querySelectorAll("input, select, textarea, button")),o=new FormData;return e.forEach((t=>{if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLButtonElement))return;if(!t.name||t.hasAttribute("data-no-serialize"))return;const{name:e,type:r}=t;if("file"===r)if("true"===t.getAttribute("multiple")){const r=t.files;if(r)for(let t=0;t<r.length;t++)o.append(`${e}[${t}]`,r[t])}else{const r=t.files;r&&r[0]&&o.append(e,r[0])}else{let i;if("select-one"===r||"select-multiple"===r){const n=t;if("select-multiple"===r){Array.from(n.selectedOptions).map((t=>t.value)).forEach(((t,r)=>{o.append(`${e}[${r}]`,t)}))}else i=n.value,i&&o.append(e,i)}else if("tel"===r)i=t.value.split(/[\s()-]/).join("").replace(/^8/,"+7");else if("checkbox"===r||"radio"===r){if(!t.checked)return;i=t.value}else if("date"===r){const e=t.getAttribute("data-date-format");i=e?function(t,e){const o=new Date(t),r=t=>t.toString().padStart(2,"0"),i=r(o.getDate()),n=r(o.getMonth()+1),s=o.getFullYear().toString();return e.replace("dd",i).replace("mm",n).replace("yyyy",s)}(t.value,e):t.value}else i=t.value;i&&"select-one"!==r&&"select-multiple"!==r&&o.append(e,i)}})),o}var r;"function"==typeof SuppressedError&&SuppressedError;const i=Symbol.for("FormFather.validators"),n=null!==(r=globalThis[i])&&void 0!==r?r:globalThis[i]=new Map;function s(t,e,o,{override:r=!1}={}){!n.has(t)||r?n.set(t,{fn:e,defaultMessage:o}):console.warn(`[FormFather] Validator "${t}" already exists; pass { override: true } to replace`)}const a=t=>n.get(t);var l;s("required",((t,e,o)=>{if(e&&e.type){if("checkbox"===e.type)return e.checked;if("radio"===e.type){const t=o.querySelectorAll(`input[type="radio"][name="${e.name}"]`);return Array.from(t).some((t=>t.checked))}}return t.trim().length>0}),"Пустое значение"),s("email",(t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)),"Неверный формат"),s("tel",(t=>/^\+7\d{10}$/.test(t)),"Неверный формат"),s("url",(t=>/^(https?:\/\/).+\..+/.test(t)),"Неверный формат"),s("not-numbers",(t=>!/[0-9]/.test(t)),"Неверный формат");const c=Symbol.for("formfather.shared"),d=null!==(l=globalThis[c])&&void 0!==l?l:globalThis[c]={defaultParams:{},defaultValidationSchema:void 0},u={tel:{selector:'input[type="tel"]',rules:["tel"]},email:{selector:'input[type="email"]',rules:["email"]},required:{selector:"[required]",rules:["required"]},url:{selector:'input[type="url"]',rules:["url"]},"not-numbers":{selector:'input[data-validate="not-numbers"]',rules:["not-numbers"]}};class p{static get defaultParams(){return d.defaultParams}static set defaultParams(t){d.defaultParams=t}static get defaultValidationSchema(){var t;return null!==(t=d.defaultValidationSchema)&&void 0!==t?t:d.defaultValidationSchema=u}static set defaultValidationSchema(t){d.defaultValidationSchema=t}constructor(t,e){this.$submit=null,this.waitResponse=!1,this.inputs=null,this._anim={duration:220,easing:"ease",paddingTopOpened:16,iconDuration:700},this.$el=t,this.options=e;this.config=Object.assign({},{onSubmit:()=>{},onResponse:()=>{},onResponseSuccess:()=>{},onResponseUnsuccess:()=>{},customTypeError:null,loaderColor:"#fff",showLoaderButton:!0,scrollToFirstErroredInput:!0,logging:!1,inputSelector:".input",inputWrapperSelector:".input-primary"},p.defaultParams,e),this.$el?(this.$submit=this.$el.querySelector('input[type="submit"], button[type="submit"]'),this.isCorrectArguments()&&this.initialization()):console.warn("Empty $el")}getOptions(){return this.options}static setDefaultParams(t){this.defaultParams=Object.assign(Object.assign({},this.defaultParams),t)}initialization(){this.inputs=this.$el.querySelectorAll(this.config.inputSelector);const t=()=>e(this,void 0,void 0,(function*(){var t;const e=this.$el.getAttribute("action")||"",r=(null===(t=this.$el.getAttribute("method"))||void 0===t?void 0:t.toUpperCase())||"POST",i=this.$el.getAttribute("enctype")||"application/x-www-form-urlencoded";let n=null,s={};const a=o(this.$el);let l={};if(a.forEach(((t,e)=>{l[e]=t})),this.config.logging)for(const t of a.keys())console.log(a.get(t));switch("function"==typeof this.config.wrapData&&(l=this.config.wrapData(l)),i){case"application/x-www-form-urlencoded":n=new URLSearchParams(o(this.$el)).toString(),s["Content-Type"]="application/x-www-form-urlencoded";break;case"multipart/form-data":n=o(this.$el);break;case"text/plain":n=Array.from(o(this.$el)).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("\n"),s["Content-Type"]="text/plain";break;case"application/json":n=JSON.stringify(l),s["Content-Type"]="application/json";break;default:console.warn(`Неизвестный enctype: ${i}. Используется application/x-www-form-urlencoded.`),n=new URLSearchParams(o(this.$el)).toString(),s["Content-Type"]="application/x-www-form-urlencoded"}return fetch(e,{method:r,body:n,headers:s})})),r=()=>e(this,void 0,void 0,(function*(){var e,o,r,i,n,s,a,l;if(!this.waitResponse){!0===this.config.showLoaderButton&&this.showLoader(),null===(o=(e=this.config).onSubmit)||void 0===o||o.call(e,this),this.waitResponse=!0;const c=yield t(),d=yield c.json();if(this.waitResponse=!1,!0===this.config.showLoaderButton&&this.hideLoader(),null===(i=(r=this.config).onResponse)||void 0===i||i.call(r,d,this),200===c.status){if(!0===d.success)null===(s=(n=this.config).onResponseSuccess)||void 0===s||s.call(n,d,this);else if(null===(l=(a=this.config).onResponseUnsuccess)||void 0===l||l.call(a,d,this),!0===d.error&&(d["error-msg"]&&this.showErrorForm(d["error-msg"]),d.errors)){const t=[];d.errors.forEach((e=>{const o=this.$el.querySelector(`input[name="${e.name}"]`);o?(t.push(o),this.showError(o,e["error-msg"])):console.warn(`Не найдено поле с именем: ${e.name}, для вывода ошибки: ${e["error-msg"]}`)})),!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(t)}!function(t){if(Object.prototype.hasOwnProperty.call(t,"redirect-url"))window.location.href=t["redirect-url"];else if(Object.prototype.hasOwnProperty.call(t,"reload"))!0===t.reload&&window.location.reload();else if(Object.prototype.hasOwnProperty.call(t,"toast")){const e=t.toast;(Array.isArray(e)?e:[e]).forEach((t=>{window.showToast(t)}))}else Object.prototype.hasOwnProperty.call(t,"error-toast")&&window.showToast(t["error-toast"])}(d)}}}));this._onSubmitHandler=t=>e(this,void 0,void 0,(function*(){var e,o,i,n;t.preventDefault(),null===(o=(e=this.config).onBeforeValidate)||void 0===o||o.call(e,this);const s=yield this.validate();null===(n=(i=this.config).onAfterValidate)||void 0===n||n.call(i,s,this),s&&r()})),this.$el.addEventListener("submit",this._onSubmitHandler)}showError(t,e){(function(t,e){if(null==t)return null;let o=t;for(;o;){if(o.matches(e))return o;o=o.parentElement}return null})(t,this.config.inputWrapperSelector).showError(e)}showLoader(){var t;const e=`\n\t\t\t<svg height="38" viewBox="0 0 38 38" width="38" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<defs>\n\t\t\t\t<linearGradient id="form-father-loader" x1="8.042%" x2="65.682%" y1="0%" y2="23.865%">\n\t\t\t\t\t<stop offset="0%" stop-color="${this.config.loaderColor}" stop-opacity="0"/>\n\t\t\t\t\t<stop offset="63.146%" stop-color="${this.config.loaderColor}" stop-opacity=".631"/>\n\t\t\t\t\t<stop offset="100%" stop-color="${this.config.loaderColor}"/>\n\t\t\t\t</linearGradient>\n\t\t\t\t</defs>\n\t\t\t\t<g fill-rule="evenodd" fill="none">\n\t\t\t\t<g transform="translate(1 1)">\n\t\t\t\t\t<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke-width="5" stroke="url(#form-father-loader)"></path>\n\t\t\t\t\t<circle cx="36" cy="18" fill="${this.config.loaderColor}" r="1"></circle>\n\t\t\t\t</g>\n\t\t\t\t</g>\n\t\t\t</svg>\n\t\t`,o=document.createElement("span");o.innerHTML=e,o.className="button__loader",null===(t=this.$submit)||void 0===t||t.insertAdjacentElement("afterbegin",o),requestAnimationFrame((()=>{o.setAttribute("data-showed","")}))}hideLoader(){var t,e;null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const o=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");o&&(o.classList.remove("active"),o.removeAttribute("data-showed"),setTimeout((()=>{o.remove()}),250))}hideError(t){const e=t.parentElement;e&&e.classList.contains("input__wrapper")&&(e.getAttribute("data-type-error"),e.classList.remove("input__wrapper--error"))}scrollToFirstErroredInput(t){if(t.length>0){const e=Array.from(this.$el.querySelectorAll("input"));let o=null,r=1/0;if(t.forEach((t=>{const i=e.findIndex((e=>e===t));i<r&&(r=i,o=t)})),o){const t=o.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop,r=t.top+e-window.innerHeight/2;document.documentElement.setAttribute("data-now-scrolling",""),window.scrollTo({top:r,behavior:"smooth"}),setTimeout((()=>{document.documentElement.removeAttribute("data-now-scrolling")}),800)}}}validate(){return e(this,arguments,void 0,(function*(t=this.$el){const o=Object.assign(Object.assign({},p.defaultValidationSchema||{}),this.config.validationSchema||{}),r=t=>console.warn(`[FormFather] Unknown validation rule "${t}"`),i=[],n=new WeakSet;let s=!0;const l=(t,e=[])=>{var o;const i=[];t.hasAttribute("required")&&i.push("required"),i.push(...e);const n=(null!==(o=t.getAttribute("data-custom-validate"))&&void 0!==o?o:"").split(",").map((t=>t.trim())).filter(Boolean);i.push(...n);const s=[];for(const t of i){const e="string"==typeof t?t:t.rule;a(e)?s.push(t):r(e)}return s},c=(o,r,...n)=>e(this,[o,r,...n],void 0,(function*(e,o,r={}){var n;if(e.hasAttribute("data-no-validate"))return;if(!("checkbox"===e.type||"radio"===e.type?!e.checked:0===e.value.trim().length)||o.includes("required")){for(const l of o){const{rule:o,params:c}="string"==typeof l?{rule:l,params:void 0}:l,d=a(o);if(!(yield d.fn(e.value,e,t,c))){s=!1;const t=null!==(n=r[o])&&void 0!==n?n:d.defaultMessage;return this.showError(e,t),void i.push(e)}}this.hideError(e)}else this.hideError(e)}));for(const[e,r]of Object.entries(o)){const{selector:o,rules:i=[],messages:s={}}=r,a=o?t.querySelectorAll(o):t.querySelectorAll(`[data-validate="${e}"]`);for(const t of Array.from(a))n.has(t)||(n.add(t),yield c(t,l(t,i),s))}const d=Array.from(t.querySelectorAll("[data-custom-validate]")).filter((t=>!n.has(t)));for(const t of d)n.add(t),yield c(t,l(t,[]));return!s&&this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(i.filter((t=>!t.hasAttribute("data-no-error-scroll")))),s}))}disableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.setAttribute("disabled","")}enableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.removeAttribute("disabled")}clearInputs(){var t;null===(t=this.inputs)||void 0===t||t.forEach((t=>{var e;const o=t;"radio"===o.type||"checkbox"===o.type?o.checked=!1:(o.value="",null===(e=o.parentElement)||void 0===e||e.classList.remove("filled"),o.dispatchEvent(new Event("input")))}))}_prefersReducedMotion(){var t;return"undefined"!=typeof window&&(null===(t=window.matchMedia)||void 0===t?void 0:t.call(window,"(prefers-reduced-motion: reduce)").matches)}_canAnimate(t){return!(!t||!("animate"in t)||this._prefersReducedMotion())}_cancelAnimations(t){var e;null===(e=null==t?void 0:t.getAnimations)||void 0===e||e.call(t).forEach((t=>t.cancel()))}showErrorForm(t){var e;const o=this.$el.querySelectorAll(this.config.inputWrapperSelector),r=o[o.length-1];let i=this.$el.querySelector(".error-block-under-input__wrapper");i&&r.nextElementSibling===i?(i.style.boxSizing="border-box",i.style.overflow="hidden"):(i=document.createElement("div"),i.className="error-block-under-input__wrapper",i.innerHTML='\n <div class="error-block-under-input error-block-under-input--warning" style="display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;">\n <div class="error-block-under-input__icon-wrapper" style="position:relative;width:20px;height:20px;">\n <span class="error-block-under-input__icon" style="display:block;width:20px;height:20px;"></span>\n <span class="error-block-under-input__icon error-block-under-input__icon--animated" style="display:block;position:absolute;inset:0;"></span>\n </div>\n <p class="error-block-under-input__text" style="margin:0;">\n <span class="error-block-under-input__main-text"></span>\n <span class="error-block-under-input__secondary-text"></span>\n </p>\n </div>\n ',Object.assign(i.style,{boxSizing:"border-box",overflow:"hidden",height:"0px",paddingTop:"0px",opacity:"0"}),r.insertAdjacentElement("afterend",i)),i.querySelector(".error-block-under-input__main-text").textContent=t;const n=i.querySelector(".error-block-under-input__secondary-text");n&&(n.textContent=""),null===(e=i.querySelector(".error-block-under-input"))||void 0===e||e.classList.remove("error-block-under-input--success"),i.querySelector(".error-block-under-input");const s=i.style.height,a=i.style.paddingTop;i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`;const l=i.clientHeight;if(i.style.height=s||"0px",i.style.paddingTop=a||"0px",parseFloat(i.style.height)===l&&1===parseFloat(i.style.opacity||"1"))this._ringIcon(i);else{if(this._cancelAnimations(i),this._canAnimate(i)){i.animate([{height:`${parseFloat(i.style.height)||0}px`,paddingTop:`${parseFloat(i.style.paddingTop)||0}px`,opacity:parseFloat(i.style.opacity||"0")},{height:`${l}px`,paddingTop:`${this._anim.paddingTopOpened}px`,opacity:1}],{duration:this._anim.duration,easing:this._anim.easing,fill:"forwards"}).addEventListener("finish",(()=>{i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`,i.style.opacity="1"}))}else i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`,i.style.opacity="1";this._ringIcon(i)}this.$el.addEventListener("input",(()=>this.hideErrorForm()),{passive:!0,once:!0})}hideErrorForm(){const t=this.$el.querySelectorAll(this.config.inputWrapperSelector),e=t[t.length-1].nextElementSibling;if(!e||!e.classList.contains("error-block-under-input__wrapper"))return;if((""===e.style.height||"auto"===e.style.height)&&(e.style.height=`${e.clientHeight}px`),e.style.paddingTop=e.style.paddingTop||`${this._anim.paddingTopOpened}px`,e.style.opacity=e.style.opacity||"1",this._cancelAnimations(e),this._canAnimate(e)){e.animate([{height:`${parseFloat(e.style.height)||e.clientHeight}px`,paddingTop:`${parseFloat(e.style.paddingTop)||this._anim.paddingTopOpened}px`,opacity:parseFloat(e.style.opacity||"1")},{height:"0px",paddingTop:"0px",opacity:0}],{duration:this._anim.duration,easing:this._anim.easing,fill:"forwards"}).addEventListener("finish",(()=>{e.remove()}))}else e.remove()}_ringIcon(t){const e=t.querySelector(".error-block-under-input__icon--animated");e&&(this._cancelAnimations(e),this._canAnimate(e)&&e.animate([{transform:"rotate(0deg) scale(1)",opacity:0},{transform:"rotate(-8deg) scale(1.05)",opacity:1,offset:.15},{transform:"rotate(8deg) scale(1.05)",opacity:1,offset:.3},{transform:"rotate(-6deg) scale(1.03)",opacity:1,offset:.45},{transform:"rotate(6deg) scale(1.03)",opacity:1,offset:.6},{transform:"rotate(0deg) scale(1)",opacity:0}],{duration:this._anim.iconDuration,easing:"ease"}))}destroy(){var t,e;this._onSubmitHandler&&(this.$el.removeEventListener("submit",this._onSubmitHandler),this._onSubmitHandler=void 0);const o=this.$el.querySelector(".error-block-under-input__wrapper");o&&(this._cancelAnimations(o),o.remove()),null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const r=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");r&&r.remove();this.$el.querySelectorAll("input, textarea").forEach((t=>{t instanceof HTMLInputElement&&this.hideError(t)})),document.documentElement.removeAttribute("data-now-scrolling"),this.inputs=null,this.$submit=null,this.waitResponse=!1}isCorrectArguments(){return"FORM"!==this.$el.tagName?(console.warn("$el не является тегом form"),!1):!!this.$submit||(console.warn("В форме нет кнопки с типом submit"),!1)}}return t.default=p,t.getAllValidators=function(){return new Map(n)},t.getValidator=a,t.registerValidator=s,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
1
+ var FormFather=function(t){"use strict";function e(t,e,o,r){return new(o||(o=Promise))((function(i,n){function s(t){try{l(r.next(t))}catch(t){n(t)}}function a(t){try{l(r.throw(t))}catch(t){n(t)}}function l(t){var e;t.done?i(t.value):(e=t.value,e instanceof o?e:new o((function(t){t(e)}))).then(s,a)}l((r=r.apply(t,e||[])).next())}))}function o(t){const e="FORM"===t.tagName?Array.from(t.elements):Array.from(t.querySelectorAll("input, select, textarea, button")),o=new FormData;return e.forEach((t=>{if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement||t instanceof HTMLButtonElement))return;if(!t.name||t.hasAttribute("data-no-serialize"))return;const{name:e,type:r}=t;if("file"===r)if("true"===t.getAttribute("multiple")){const r=t.files;if(r)for(let t=0;t<r.length;t++)o.append(`${e}[${t}]`,r[t])}else{const r=t.files;r&&r[0]&&o.append(e,r[0])}else{let i;if("select-one"===r||"select-multiple"===r){const n=t;if("select-multiple"===r){Array.from(n.selectedOptions).map((t=>t.value)).forEach(((t,r)=>{o.append(`${e}[${r}]`,t)}))}else i=n.value,i&&o.append(e,i)}else if("tel"===r)i=t.value.split(/[\s()-]/).join("").replace(/^8/,"+7");else if("checkbox"===r||"radio"===r){if(!t.checked)return;i=t.value}else if("date"===r){const e=t.getAttribute("data-date-format");i=e?function(t,e){const o=new Date(t),r=t=>t.toString().padStart(2,"0"),i=r(o.getDate()),n=r(o.getMonth()+1),s=o.getFullYear().toString();return e.replace("dd",i).replace("mm",n).replace("yyyy",s)}(t.value,e):t.value}else i=t.value;i&&"select-one"!==r&&"select-multiple"!==r&&o.append(e,i)}})),o}var r;"function"==typeof SuppressedError&&SuppressedError;const i=Symbol.for("FormFather.validators"),n=null!==(r=globalThis[i])&&void 0!==r?r:globalThis[i]=new Map;function s(t,e,o,{override:r=!1}={}){!n.has(t)||r?n.set(t,{fn:e,defaultMessage:o}):console.warn(`[FormFather] Validator "${t}" already exists; pass { override: true } to replace`)}const a=t=>n.get(t);var l;s("required",((t,e,o)=>{if(e&&e.type){if("checkbox"===e.type)return e.checked;if("radio"===e.type){const t=o.querySelectorAll(`input[type="radio"][name="${e.name}"]`);return Array.from(t).some((t=>t.checked))}}return t.trim().length>0}),"Пустое значение"),s("email",(t=>/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)),"Неверный формат"),s("tel",(t=>/^\+7\d{10}$/.test(t)),"Неверный формат"),s("url",(t=>/^(https?:\/\/).+\..+/.test(t)),"Неверный формат"),s("not-numbers",(t=>!/[0-9]/.test(t)),"Неверный формат");const c=Symbol.for("formfather.shared"),d=null!==(l=globalThis[c])&&void 0!==l?l:globalThis[c]={defaultParams:{},defaultValidationSchema:void 0},u={tel:{selector:'input[type="tel"]',rules:["tel"]},email:{selector:'input[type="email"]',rules:["email"]},required:{selector:"[required]",rules:["required"]},url:{selector:'input[type="url"]',rules:["url"]},"not-numbers":{selector:'input[data-validate="not-numbers"]',rules:["not-numbers"]}};class p{static get defaultParams(){return d.defaultParams}static set defaultParams(t){d.defaultParams=t}static get defaultValidationSchema(){var t;return null!==(t=d.defaultValidationSchema)&&void 0!==t?t:d.defaultValidationSchema=u}static set defaultValidationSchema(t){d.defaultValidationSchema=t}constructor(t,e){this.$submit=null,this.waitResponse=!1,this.inputs=null,this._anim={duration:220,easing:"ease",paddingTopOpened:16,iconDuration:700},this.$el=t,this.options=e;this.config=Object.assign({},{onSubmit:()=>{},onResponse:()=>{},onResponseSuccess:()=>{},onResponseUnsuccess:()=>{},customTypeError:null,loaderColor:"#fff",showLoaderButton:!0,scrollToFirstErroredInput:!0,logging:!1,inputSelector:".input",inputWrapperSelector:".input-primary"},p.defaultParams,e),this.$el?(this.$submit=this.$el.querySelector('input[type="submit"], button[type="submit"]'),this.isCorrectArguments()&&this.initialization()):console.warn("Empty $el")}getOptions(){return this.options}static setDefaultParams(t){this.defaultParams=Object.assign(Object.assign({},this.defaultParams),t)}initialization(){this.inputs=this.$el.querySelectorAll(this.config.inputSelector);const t=()=>e(this,void 0,void 0,(function*(){var t;const e=this.$el.getAttribute("action")||"",r=(null===(t=this.$el.getAttribute("method"))||void 0===t?void 0:t.toUpperCase())||"POST",i=this.$el.getAttribute("enctype")||"application/x-www-form-urlencoded";let n=null,s={};const a=o(this.$el);let l={};if(a.forEach(((t,e)=>{l[e]=t})),this.config.logging)for(const t of a.keys())console.log(a.get(t));switch("function"==typeof this.config.wrapData&&(l=this.config.wrapData(l)),i){case"application/x-www-form-urlencoded":n=new URLSearchParams(o(this.$el)).toString(),s["Content-Type"]="application/x-www-form-urlencoded";break;case"multipart/form-data":n=o(this.$el);break;case"text/plain":n=Array.from(o(this.$el)).map((([t,e])=>`${encodeURIComponent(t)}=${encodeURIComponent(e)}`)).join("\n"),s["Content-Type"]="text/plain";break;case"application/json":n=JSON.stringify(l),s["Content-Type"]="application/json";break;default:console.warn(`Неизвестный enctype: ${i}. Используется application/x-www-form-urlencoded.`),n=new URLSearchParams(o(this.$el)).toString(),s["Content-Type"]="application/x-www-form-urlencoded"}return fetch(e,{method:r,body:n,headers:s})})),r=()=>e(this,void 0,void 0,(function*(){var e,o,r,i,n,s,a,l;if(!this.waitResponse){!0===this.config.showLoaderButton&&this.showLoader(),null===(o=(e=this.config).onSubmit)||void 0===o||o.call(e,this),this.waitResponse=!0;const c=yield t(),d=yield c.json();if(this.waitResponse=!1,!0===this.config.showLoaderButton&&this.hideLoader(),null===(i=(r=this.config).onResponse)||void 0===i||i.call(r,d,this),200===c.status){if(!0===d.success)null===(s=(n=this.config).onResponseSuccess)||void 0===s||s.call(n,d,this);else if(null===(l=(a=this.config).onResponseUnsuccess)||void 0===l||l.call(a,d,this),!0===d.error&&(d["error-msg"]&&this.showErrorForm(d["error-msg"]),d.errors)){const t=[];d.errors.forEach((e=>{const o=this.$el.querySelector(`input[name="${e.name}"]`);o?(t.push(o),this.showError(o,e["error-msg"])):console.warn(`Не найдено поле с именем: ${e.name}, для вывода ошибки: ${e["error-msg"]}`)})),!0===this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(t)}!function(t){if(Object.prototype.hasOwnProperty.call(t,"redirect-url"))if(t["redirect-url-delay"]){const e=Number(t["redirect-url-delay"]);setTimeout((()=>{window.location.href=t["redirect-url"]}),e)}else window.location.href=t["redirect-url"];else if(Object.prototype.hasOwnProperty.call(t,"reload")){if(!0===t.reload)if(t["reload-delay"]){const e=Number(t["reload-delay"]);setTimeout((()=>{window.location.reload()}),e)}else window.location.reload()}else if(Object.prototype.hasOwnProperty.call(t,"toast")){const e=t.toast;(Array.isArray(e)?e:[e]).forEach((t=>{window.showToast(t)}))}else Object.prototype.hasOwnProperty.call(t,"error-toast")&&window.showToast(t["error-toast"])}(d)}}}));this._onSubmitHandler=t=>e(this,void 0,void 0,(function*(){var e,o,i,n;t.preventDefault(),null===(o=(e=this.config).onBeforeValidate)||void 0===o||o.call(e,this);const s=yield this.validate();null===(n=(i=this.config).onAfterValidate)||void 0===n||n.call(i,s,this),s&&r()})),this.$el.addEventListener("submit",this._onSubmitHandler)}showError(t,e){(function(t,e){if(null==t)return null;let o=t;for(;o;){if(o.matches(e))return o;o=o.parentElement}return null})(t,this.config.inputWrapperSelector).showError(e)}showLoader(){var t;const e=`\n\t\t\t<svg height="38" viewBox="0 0 38 38" width="38" xmlns="http://www.w3.org/2000/svg">\n\t\t\t\t<defs>\n\t\t\t\t<linearGradient id="form-father-loader" x1="8.042%" x2="65.682%" y1="0%" y2="23.865%">\n\t\t\t\t\t<stop offset="0%" stop-color="${this.config.loaderColor}" stop-opacity="0"/>\n\t\t\t\t\t<stop offset="63.146%" stop-color="${this.config.loaderColor}" stop-opacity=".631"/>\n\t\t\t\t\t<stop offset="100%" stop-color="${this.config.loaderColor}"/>\n\t\t\t\t</linearGradient>\n\t\t\t\t</defs>\n\t\t\t\t<g fill-rule="evenodd" fill="none">\n\t\t\t\t<g transform="translate(1 1)">\n\t\t\t\t\t<path d="M36 18c0-9.94-8.06-18-18-18" id="Oval-2" stroke-width="5" stroke="url(#form-father-loader)"></path>\n\t\t\t\t\t<circle cx="36" cy="18" fill="${this.config.loaderColor}" r="1"></circle>\n\t\t\t\t</g>\n\t\t\t\t</g>\n\t\t\t</svg>\n\t\t`,o=document.createElement("span");o.innerHTML=e,o.className="button__loader",null===(t=this.$submit)||void 0===t||t.insertAdjacentElement("afterbegin",o),requestAnimationFrame((()=>{o.setAttribute("data-showed","")}))}hideLoader(){var t,e;null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const o=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");o&&(o.classList.remove("active"),o.removeAttribute("data-showed"),setTimeout((()=>{o.remove()}),250))}hideError(t){const e=t.parentElement;e&&e.classList.contains("input__wrapper")&&(e.getAttribute("data-type-error"),e.classList.remove("input__wrapper--error"))}scrollToFirstErroredInput(t){if(t.length>0){const e=Array.from(this.$el.querySelectorAll("input"));let o=null,r=1/0;if(t.forEach((t=>{const i=e.findIndex((e=>e===t));i<r&&(r=i,o=t)})),o){const t=o.getBoundingClientRect(),e=window.pageYOffset||document.documentElement.scrollTop,r=t.top+e-window.innerHeight/2;document.documentElement.setAttribute("data-now-scrolling",""),window.scrollTo({top:r,behavior:"smooth"}),setTimeout((()=>{document.documentElement.removeAttribute("data-now-scrolling")}),800)}}}validate(){return e(this,arguments,void 0,(function*(t=this.$el){const o=Object.assign(Object.assign({},p.defaultValidationSchema||{}),this.config.validationSchema||{}),r=t=>console.warn(`[FormFather] Unknown validation rule "${t}"`),i=[],n=new WeakSet;let s=!0;const l=(t,e=[])=>{var o;const i=[];t.hasAttribute("required")&&i.push("required"),i.push(...e);const n=(null!==(o=t.getAttribute("data-custom-validate"))&&void 0!==o?o:"").split(",").map((t=>t.trim())).filter(Boolean);i.push(...n);const s=[];for(const t of i){const e="string"==typeof t?t:t.rule;a(e)?s.push(t):r(e)}return s},c=(o,r,...n)=>e(this,[o,r,...n],void 0,(function*(e,o,r={}){if(e.hasAttribute("data-no-validate"))return;if(!("checkbox"===e.type||"radio"===e.type?!e.checked:0===e.value.trim().length)||o.includes("required")){for(const n of o){const{rule:o,params:l}="string"==typeof n?{rule:n,params:void 0}:n,c=a(o),d=yield c.fn(e.value,e,t,l),u="object"==typeof d&&null!==d,p=u?!0===d.valid:!!d;if(u&&d.effect&&(yield d.effect({value:e.value,$input:e,$form:t,params:l})),!p){s=!1;const t=d,n=u&&"string"==typeof t.message&&t.message||r[o]||c.defaultMessage;return this.showError(e,n),void i.push(e)}if(u&&d.stopOthers)return}this.hideError(e)}else this.hideError(e)}));for(const[e,r]of Object.entries(o)){const{selector:o,rules:i=[],messages:s={}}=r,a=o?t.querySelectorAll(o):t.querySelectorAll(`[data-validate="${e}"]`);for(const t of Array.from(a))n.has(t)||(n.add(t),yield c(t,l(t,i),s))}const d=Array.from(t.querySelectorAll("[data-custom-validate]")).filter((t=>!n.has(t)));for(const t of d)n.add(t),yield c(t,l(t,[]));return!s&&this.config.scrollToFirstErroredInput&&this.scrollToFirstErroredInput(i.filter((t=>!t.hasAttribute("data-no-error-scroll")))),s}))}disableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.setAttribute("disabled","")}enableSubmit(){var t;null===(t=this.$submit)||void 0===t||t.removeAttribute("disabled")}clearInputs(){var t;null===(t=this.inputs)||void 0===t||t.forEach((t=>{var e;const o=t;"radio"===o.type||"checkbox"===o.type?o.checked=!1:(o.value="",null===(e=o.parentElement)||void 0===e||e.classList.remove("filled"),o.dispatchEvent(new Event("input")))}))}_prefersReducedMotion(){var t;return"undefined"!=typeof window&&(null===(t=window.matchMedia)||void 0===t?void 0:t.call(window,"(prefers-reduced-motion: reduce)").matches)}_canAnimate(t){return!(!t||!("animate"in t)||this._prefersReducedMotion())}_cancelAnimations(t){var e;null===(e=null==t?void 0:t.getAnimations)||void 0===e||e.call(t).forEach((t=>t.cancel()))}showErrorForm(t){var e;const o=this.$el.querySelectorAll(this.config.inputWrapperSelector),r=o[o.length-1];let i=this.$el.querySelector(".error-block-under-input__wrapper");i&&r.nextElementSibling===i?(i.style.boxSizing="border-box",i.style.overflow="hidden"):(i=document.createElement("div"),i.className="error-block-under-input__wrapper",i.innerHTML='\n <div class="error-block-under-input error-block-under-input--warning" style="display:grid;grid-template-columns:auto 1fr;gap:8px;align-items:start;">\n <div class="error-block-under-input__icon-wrapper" style="position:relative;width:20px;height:20px;">\n <span class="error-block-under-input__icon" style="display:block;width:20px;height:20px;"></span>\n <span class="error-block-under-input__icon error-block-under-input__icon--animated" style="display:block;position:absolute;inset:0;"></span>\n </div>\n <p class="error-block-under-input__text" style="margin:0;">\n <span class="error-block-under-input__main-text"></span>\n <span class="error-block-under-input__secondary-text"></span>\n </p>\n </div>\n ',Object.assign(i.style,{boxSizing:"border-box",overflow:"hidden",height:"0px",paddingTop:"0px",opacity:"0"}),r.insertAdjacentElement("afterend",i)),i.querySelector(".error-block-under-input__main-text").textContent=t;const n=i.querySelector(".error-block-under-input__secondary-text");n&&(n.textContent=""),null===(e=i.querySelector(".error-block-under-input"))||void 0===e||e.classList.remove("error-block-under-input--success"),i.querySelector(".error-block-under-input");const s=i.style.height,a=i.style.paddingTop;i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`;const l=i.clientHeight;if(i.style.height=s||"0px",i.style.paddingTop=a||"0px",parseFloat(i.style.height)===l&&1===parseFloat(i.style.opacity||"1"))this._ringIcon(i);else{if(this._cancelAnimations(i),this._canAnimate(i)){i.animate([{height:`${parseFloat(i.style.height)||0}px`,paddingTop:`${parseFloat(i.style.paddingTop)||0}px`,opacity:parseFloat(i.style.opacity||"0")},{height:`${l}px`,paddingTop:`${this._anim.paddingTopOpened}px`,opacity:1}],{duration:this._anim.duration,easing:this._anim.easing,fill:"forwards"}).addEventListener("finish",(()=>{i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`,i.style.opacity="1"}))}else i.style.height="auto",i.style.paddingTop=`${this._anim.paddingTopOpened}px`,i.style.opacity="1";this._ringIcon(i)}this.$el.addEventListener("input",(()=>this.hideErrorForm()),{passive:!0,once:!0})}hideErrorForm(){const t=this.$el.querySelectorAll(this.config.inputWrapperSelector),e=t[t.length-1].nextElementSibling;if(!e||!e.classList.contains("error-block-under-input__wrapper"))return;if((""===e.style.height||"auto"===e.style.height)&&(e.style.height=`${e.clientHeight}px`),e.style.paddingTop=e.style.paddingTop||`${this._anim.paddingTopOpened}px`,e.style.opacity=e.style.opacity||"1",this._cancelAnimations(e),this._canAnimate(e)){e.animate([{height:`${parseFloat(e.style.height)||e.clientHeight}px`,paddingTop:`${parseFloat(e.style.paddingTop)||this._anim.paddingTopOpened}px`,opacity:parseFloat(e.style.opacity||"1")},{height:"0px",paddingTop:"0px",opacity:0}],{duration:this._anim.duration,easing:this._anim.easing,fill:"forwards"}).addEventListener("finish",(()=>{e.remove()}))}else e.remove()}_ringIcon(t){const e=t.querySelector(".error-block-under-input__icon--animated");e&&(this._cancelAnimations(e),this._canAnimate(e)&&e.animate([{transform:"rotate(0deg) scale(1)",opacity:0},{transform:"rotate(-8deg) scale(1.05)",opacity:1,offset:.15},{transform:"rotate(8deg) scale(1.05)",opacity:1,offset:.3},{transform:"rotate(-6deg) scale(1.03)",opacity:1,offset:.45},{transform:"rotate(6deg) scale(1.03)",opacity:1,offset:.6},{transform:"rotate(0deg) scale(1)",opacity:0}],{duration:this._anim.iconDuration,easing:"ease"}))}destroy(){var t,e;this._onSubmitHandler&&(this.$el.removeEventListener("submit",this._onSubmitHandler),this._onSubmitHandler=void 0);const o=this.$el.querySelector(".error-block-under-input__wrapper");o&&(this._cancelAnimations(o),o.remove()),null===(t=this.$submit)||void 0===t||t.classList.remove("button--loading");const r=null===(e=this.$submit)||void 0===e?void 0:e.querySelector(".button__loader");r&&r.remove();this.$el.querySelectorAll("input, textarea").forEach((t=>{t instanceof HTMLInputElement&&this.hideError(t)})),document.documentElement.removeAttribute("data-now-scrolling"),this.inputs=null,this.$submit=null,this.waitResponse=!1}isCorrectArguments(){return"FORM"!==this.$el.tagName?(console.warn("$el не является тегом form"),!1):!!this.$submit||(console.warn("В форме нет кнопки с типом submit"),!1)}}return t.default=p,t.getAllValidators=function(){return new Map(n)},t.getValidator=a,t.registerValidator=s,Object.defineProperty(t,"__esModule",{value:!0}),t}({});
2
2
  //# sourceMappingURL=FormFather.min.js.map
package/index.d.ts CHANGED
@@ -1,4 +1,19 @@
1
- type ValidatorFn = (value: string, $input: HTMLInputElement | HTMLTextAreaElement, $form: HTMLElement, params?: any) => boolean | Promise<boolean>;
1
+ type ValidatorEffectCtx = {
2
+ value: string;
3
+ $input: HTMLInputElement | HTMLTextAreaElement;
4
+ $form: HTMLElement;
5
+ params?: any;
6
+ };
7
+ type ValidatorResult = {
8
+ valid: boolean;
9
+ /** Сообщение об ошибке, если нужно переопределить дефолт */
10
+ message?: string;
11
+ /** Выполнить сайд-эффект (подсветка, иконки, тексты и т.п.) */
12
+ effect?: (ctx: ValidatorEffectCtx) => void | Promise<void>;
13
+ /** Остановить дальнейшие правила для поля (даже если valid=true). Полезно, если валидатор полностью «ведёт» поле. */
14
+ stopOthers?: boolean;
15
+ };
16
+ type ValidatorFn = (value: string, $input: HTMLInputElement | HTMLTextAreaElement, $form: HTMLElement, params?: any) => boolean | Promise<boolean> | ValidatorResult | Promise<ValidatorResult>;
2
17
  interface Validator {
3
18
  fn: ValidatorFn;
4
19
  defaultMessage: string;
@@ -182,4 +197,4 @@ declare class Form {
182
197
  private isCorrectArguments;
183
198
  }
184
199
 
185
- export { Form as default, getAllValidators, getValidator, registerValidator };
200
+ export { type ValidatorEffectCtx, type ValidatorResult, Form as default, getAllValidators, getValidator, registerValidator };
package/index.js CHANGED
@@ -161,11 +161,27 @@ function serializeToFormData($element) {
161
161
  */
162
162
  function parseCommonResponseProperties(responseBody) {
163
163
  if (Object.prototype.hasOwnProperty.call(responseBody, 'redirect-url')) {
164
- window.location.href = responseBody['redirect-url'];
164
+ if (responseBody['redirect-url-delay']) {
165
+ const redirectUrlDelay = Number(responseBody['redirect-url-delay']);
166
+ setTimeout(() => {
167
+ window.location.href = responseBody['redirect-url'];
168
+ }, redirectUrlDelay);
169
+ }
170
+ else {
171
+ window.location.href = responseBody['redirect-url'];
172
+ }
165
173
  }
166
174
  else if (Object.prototype.hasOwnProperty.call(responseBody, 'reload')) {
167
175
  if (responseBody.reload === true) {
168
- window.location.reload();
176
+ if (responseBody['reload-delay']) {
177
+ const reloadDelay = Number(responseBody['reload-delay']);
178
+ setTimeout(() => {
179
+ window.location.reload();
180
+ }, reloadDelay);
181
+ }
182
+ else {
183
+ window.location.reload();
184
+ }
169
185
  }
170
186
  }
171
187
  // Не показываем тост если делается редирект или обновление страницы (чтобы небыло вспышек) - в этом случае тосты обрабытываются в ответе onResponseSuccess | onResponseUnsuccess
@@ -587,7 +603,6 @@ class Form {
587
603
  return filtered;
588
604
  };
589
605
  const validateInput = ($input_1, rules_1, ...args_1) => __awaiter(this, [$input_1, rules_1, ...args_1], void 0, function* ($input, rules, msgs = {}) {
590
- var _a;
591
606
  if ($input.hasAttribute('data-no-validate'))
592
607
  return;
593
608
  const empty = $input.type === 'checkbox' || $input.type === 'radio' ? !$input.checked : $input.value.trim().length === 0;
@@ -598,14 +613,30 @@ class Form {
598
613
  for (const r of rules) {
599
614
  const { rule, params } = typeof r === 'string' ? { rule: r, params: undefined } : r;
600
615
  const vd = getValidator(rule); // гарантированно существует
601
- const passed = yield vd.fn($input.value, $input, $block, params);
616
+ const raw = yield vd.fn($input.value, $input, $block, params);
617
+ const isObj = typeof raw === 'object' && raw !== null;
618
+ const passed = isObj ? raw.valid === true : !!raw;
619
+ // сайд-эффект (если есть)
620
+ if (isObj && raw.effect) {
621
+ yield raw.effect({
622
+ value: $input.value,
623
+ $input,
624
+ $form: $block,
625
+ params,
626
+ });
627
+ }
602
628
  if (!passed) {
603
629
  ok = false;
604
- const msg = (_a = msgs[rule]) !== null && _a !== void 0 ? _a : vd.defaultMessage;
630
+ const r = raw;
631
+ const msg = (isObj && typeof r.message === 'string' && r.message) || msgs[rule] || vd.defaultMessage;
605
632
  this.showError($input, msg);
606
633
  erroredInputs.push($input);
607
634
  return; // первую ошибку отобразили
608
635
  }
636
+ // хотим прервать цепочку правил, даже если успех
637
+ if (isObj && raw.stopOthers) {
638
+ return;
639
+ }
609
640
  }
610
641
  this.hideError($input);
611
642
  });
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form-father",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "Form Father: Библиотека для обработки форм",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,4 +1,19 @@
1
- type ValidatorFn = (value: string, $input: HTMLInputElement | HTMLTextAreaElement, $form: HTMLElement, params?: any) => boolean | Promise<boolean>;
1
+ export type ValidatorEffectCtx = {
2
+ value: string;
3
+ $input: HTMLInputElement | HTMLTextAreaElement;
4
+ $form: HTMLElement;
5
+ params?: any;
6
+ };
7
+ export type ValidatorResult = {
8
+ valid: boolean;
9
+ /** Сообщение об ошибке, если нужно переопределить дефолт */
10
+ message?: string;
11
+ /** Выполнить сайд-эффект (подсветка, иконки, тексты и т.п.) */
12
+ effect?: (ctx: ValidatorEffectCtx) => void | Promise<void>;
13
+ /** Остановить дальнейшие правила для поля (даже если valid=true). Полезно, если валидатор полностью «ведёт» поле. */
14
+ stopOthers?: boolean;
15
+ };
16
+ type ValidatorFn = (value: string, $input: HTMLInputElement | HTMLTextAreaElement, $form: HTMLElement, params?: any) => boolean | Promise<boolean> | ValidatorResult | Promise<ValidatorResult>;
2
17
  interface Validator {
3
18
  fn: ValidatorFn;
4
19
  defaultMessage: string;