form-father 0.2.3 → 0.2.5
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 +1 -1
- package/index.d.ts +20 -3
- package/index.js +53 -6
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/types/index.d.ts +3 -1
- package/types/validators.d.ts +16 -1
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.$licensesCheckbox=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.$el.addEventListener("submit",(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()}))))}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"}))}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"))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={}){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
|
|
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;
|
|
@@ -93,7 +108,7 @@ declare class Form {
|
|
|
93
108
|
private $submit;
|
|
94
109
|
private waitResponse;
|
|
95
110
|
private inputs;
|
|
96
|
-
private
|
|
111
|
+
private _onSubmitHandler?;
|
|
97
112
|
private static get defaultParams();
|
|
98
113
|
private static set defaultParams(value);
|
|
99
114
|
static get defaultValidationSchema(): ValidationSchema;
|
|
@@ -172,6 +187,8 @@ declare class Form {
|
|
|
172
187
|
private hideErrorForm;
|
|
173
188
|
/** Короткая анимация иконки без CSS */
|
|
174
189
|
private _ringIcon;
|
|
190
|
+
/** Полностью снимает слушатели и чистит артефакты формы. */
|
|
191
|
+
destroy(): void;
|
|
175
192
|
/**
|
|
176
193
|
* Проверяет входные данные на их корректность.
|
|
177
194
|
*
|
|
@@ -180,4 +197,4 @@ declare class Form {
|
|
|
180
197
|
private isCorrectArguments;
|
|
181
198
|
}
|
|
182
199
|
|
|
183
|
-
export { Form as default, getAllValidators, getValidator, registerValidator };
|
|
200
|
+
export { type ValidatorEffectCtx, type ValidatorResult, Form as default, getAllValidators, getValidator, registerValidator };
|
package/index.js
CHANGED
|
@@ -282,7 +282,6 @@ class Form {
|
|
|
282
282
|
this.$submit = null;
|
|
283
283
|
this.waitResponse = false;
|
|
284
284
|
this.inputs = null;
|
|
285
|
-
this.$licensesCheckbox = null;
|
|
286
285
|
/** Общие настройки анимаций (можно подправить под вкус) */
|
|
287
286
|
this._anim = {
|
|
288
287
|
duration: 220,
|
|
@@ -436,7 +435,7 @@ class Form {
|
|
|
436
435
|
}
|
|
437
436
|
}
|
|
438
437
|
});
|
|
439
|
-
this
|
|
438
|
+
this._onSubmitHandler = (e) => __awaiter(this, void 0, void 0, function* () {
|
|
440
439
|
var _a, _b, _c, _d;
|
|
441
440
|
e.preventDefault();
|
|
442
441
|
(_b = (_a = this.config).onBeforeValidate) === null || _b === void 0 ? void 0 : _b.call(_a, this);
|
|
@@ -444,7 +443,8 @@ class Form {
|
|
|
444
443
|
(_d = (_c = this.config).onAfterValidate) === null || _d === void 0 ? void 0 : _d.call(_c, isValid, this);
|
|
445
444
|
if (isValid)
|
|
446
445
|
submit();
|
|
447
|
-
})
|
|
446
|
+
});
|
|
447
|
+
this.$el.addEventListener('submit', this._onSubmitHandler);
|
|
448
448
|
}
|
|
449
449
|
/**
|
|
450
450
|
* Показывает ошибку для поля ввода.
|
|
@@ -587,7 +587,6 @@ class Form {
|
|
|
587
587
|
return filtered;
|
|
588
588
|
};
|
|
589
589
|
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
590
|
if ($input.hasAttribute('data-no-validate'))
|
|
592
591
|
return;
|
|
593
592
|
const empty = $input.type === 'checkbox' || $input.type === 'radio' ? !$input.checked : $input.value.trim().length === 0;
|
|
@@ -598,14 +597,30 @@ class Form {
|
|
|
598
597
|
for (const r of rules) {
|
|
599
598
|
const { rule, params } = typeof r === 'string' ? { rule: r, params: undefined } : r;
|
|
600
599
|
const vd = getValidator(rule); // гарантированно существует
|
|
601
|
-
const
|
|
600
|
+
const raw = yield vd.fn($input.value, $input, $block, params);
|
|
601
|
+
const isObj = typeof raw === 'object' && raw !== null;
|
|
602
|
+
const passed = isObj ? raw.valid === true : !!raw;
|
|
603
|
+
// сайд-эффект (если есть)
|
|
604
|
+
if (isObj && raw.effect) {
|
|
605
|
+
yield raw.effect({
|
|
606
|
+
value: $input.value,
|
|
607
|
+
$input,
|
|
608
|
+
$form: $block,
|
|
609
|
+
params,
|
|
610
|
+
});
|
|
611
|
+
}
|
|
602
612
|
if (!passed) {
|
|
603
613
|
ok = false;
|
|
604
|
-
const
|
|
614
|
+
const r = raw;
|
|
615
|
+
const msg = (isObj && typeof r.message === 'string' && r.message) || msgs[rule] || vd.defaultMessage;
|
|
605
616
|
this.showError($input, msg);
|
|
606
617
|
erroredInputs.push($input);
|
|
607
618
|
return; // первую ошибку отобразили
|
|
608
619
|
}
|
|
620
|
+
// хотим прервать цепочку правил, даже если успех
|
|
621
|
+
if (isObj && raw.stopOthers) {
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
609
624
|
}
|
|
610
625
|
this.hideError($input);
|
|
611
626
|
});
|
|
@@ -828,6 +843,38 @@ class Form {
|
|
|
828
843
|
{ transform: 'rotate(0deg) scale(1)', opacity: 0 },
|
|
829
844
|
], { duration: this._anim.iconDuration, easing: 'ease' });
|
|
830
845
|
}
|
|
846
|
+
/** Полностью снимает слушатели и чистит артефакты формы. */
|
|
847
|
+
destroy() {
|
|
848
|
+
var _a, _b;
|
|
849
|
+
// 1) Снять submit-слушатель
|
|
850
|
+
if (this._onSubmitHandler) {
|
|
851
|
+
this.$el.removeEventListener('submit', this._onSubmitHandler);
|
|
852
|
+
this._onSubmitHandler = undefined;
|
|
853
|
+
}
|
|
854
|
+
// 2) Удалить формовый error-блок под инпутами (если есть)
|
|
855
|
+
const formErrorWrapper = this.$el.querySelector('.error-block-under-input__wrapper');
|
|
856
|
+
if (formErrorWrapper) {
|
|
857
|
+
this._cancelAnimations(formErrorWrapper);
|
|
858
|
+
formErrorWrapper.remove();
|
|
859
|
+
}
|
|
860
|
+
// 3) Скрыть/удалить лоадер на кнопке submit
|
|
861
|
+
(_a = this.$submit) === null || _a === void 0 ? void 0 : _a.classList.remove('button--loading');
|
|
862
|
+
const btnLoader = (_b = this.$submit) === null || _b === void 0 ? void 0 : _b.querySelector('.button__loader');
|
|
863
|
+
if (btnLoader)
|
|
864
|
+
btnLoader.remove();
|
|
865
|
+
// 4) Сбросить ошибки у инпутов (если разметка позволяет)
|
|
866
|
+
const inputs = this.$el.querySelectorAll('input, textarea');
|
|
867
|
+
inputs.forEach($i => {
|
|
868
|
+
if ($i instanceof HTMLInputElement)
|
|
869
|
+
this.hideError($i);
|
|
870
|
+
});
|
|
871
|
+
// 5) Убрать возможный флаг скролла
|
|
872
|
+
document.documentElement.removeAttribute('data-now-scrolling');
|
|
873
|
+
// 6) Очистить ссылки на элементы, чтобы помочь GC
|
|
874
|
+
this.inputs = null;
|
|
875
|
+
this.$submit = null;
|
|
876
|
+
this.waitResponse = false;
|
|
877
|
+
}
|
|
831
878
|
/**
|
|
832
879
|
* Проверяет входные данные на их корректность.
|
|
833
880
|
*
|
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
package/types/index.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export default class Form {
|
|
|
83
83
|
private $submit;
|
|
84
84
|
private waitResponse;
|
|
85
85
|
private inputs;
|
|
86
|
-
private
|
|
86
|
+
private _onSubmitHandler?;
|
|
87
87
|
private static get defaultParams();
|
|
88
88
|
private static set defaultParams(value);
|
|
89
89
|
static get defaultValidationSchema(): ValidationSchema;
|
|
@@ -162,6 +162,8 @@ export default class Form {
|
|
|
162
162
|
private hideErrorForm;
|
|
163
163
|
/** Короткая анимация иконки без CSS */
|
|
164
164
|
private _ringIcon;
|
|
165
|
+
/** Полностью снимает слушатели и чистит артефакты формы. */
|
|
166
|
+
destroy(): void;
|
|
165
167
|
/**
|
|
166
168
|
* Проверяет входные данные на их корректность.
|
|
167
169
|
*
|
package/types/validators.d.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
type
|
|
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;
|