{"version":3,"file":"index.mjs","sources":[""],"sourcesContent":["import { isSelectorValid } from \"@web3r/flowerkit/css\";\r\nimport { removeChildNodes } from \"@web3r/flowerkit/dom\";\r\nimport { bubble } from \"@web3r/flowerkit/evt\";\r\nimport { wait } from \"@web3r/flowerkit/fn\";\r\nimport { getJSONFromStr } from \"@web3r/flowerkit/json\";\r\nimport { getMapFromObj, isObjEmpty } from \"@web3r/flowerkit/obj\";\r\nimport { getDocument } from \"ssr-window\";\r\nimport { string, number, boolean } from \"yup\";\r\nimport { constants } from \"../../../constants\";\r\nimport {\r\n  getUserControlledFields,\r\n  getAttr,\r\n  getInputForm,\r\n} from \"../../../utils\";\r\nimport { _isReactNode } from \"../../../utils/_isReactNode\";\r\nimport { Localisation } from \"../../localisation\";\r\nimport { selectors } from \"../constants/defaultCfg\";\r\nimport type { IFormExtendedCfg } from \"../utils/_getFormExtendedCfg\";\r\nimport { _getFormExtendedCfg } from \"../utils/_getFormExtendedCfg\";\r\n\r\n/**\r\n * Событие валидации поля формы.\r\n */\r\nexport type TValidationEvent = CustomEvent<TValidationEventDetail>;\r\n\r\n\r\n/**\r\n * Детали события валидации поля.\r\n */\r\nexport type TValidationEventDetail = {\r\n  updateValidationUI: () => void | Promise<void>;\r\n  container: HTMLElement | null;\r\n  reason: TValidationReason;\r\n  isValid: boolean;\r\n  msgCodes: TValidationMsgCodes;\r\n  msgBlock: HTMLElement | null;\r\n  validationType: string;\r\n  input: TValidationInput;\r\n  msg: Promise<string>;\r\n};\r\n\r\n\r\n/**\r\n * Допустимые типы полей для валидации.\r\n */\r\nexport type TValidationInput = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;\r\n\r\n\r\n/**\r\n * Коды сообщений по причинам валидации.\r\n */\r\nexport type TValidationMsgCodes = Record<string, string | false>;\r\n\r\n\r\n/**\r\n * Причина результата валидации.\r\n */\r\nexport type TValidationReason = \"valid\" | \"invalid\" | \"empty\";\r\n\r\n\r\n/**\r\n * Результат проверки поля в детализированном виде.\r\n */\r\nexport type TValidationResult = {\r\n  isValid: boolean;\r\n  reason: TValidationReason;\r\n};\r\n\r\n\r\n/**\r\n * Описание правила валидации.\r\n */\r\nexport type TValidationRule = {\r\n  fn: (input: TValidationInput) => boolean;\r\n  errorKeys: TValidationMsgCodes;\r\n};\r\n\r\ntype TValidationOptions = {\r\n  rules?: Record<string, TValidationRule>;\r\n  patterns?: Record<string, RegExp>;\r\n  ns?: string;\r\n};\r\ntype TValidateCfg = {\r\n  inputs?: TValidationInput[];\r\n  isIncludeDisabled?: boolean;\r\n  isBubble?: boolean;\r\n  isSilent?: boolean;\r\n  isScroll?: boolean;\r\n  ns?: string;\r\n};\r\ntype TValidateInputCfg = {\r\n  isBubble?: boolean;\r\n  isSilent?: boolean;\r\n  isDetailResult?: boolean;\r\n  getCustomValidityFn?: (input: TValidationInput) => TValidationResult;\r\n  ns?: string;\r\n  container?: HTMLElement | null;\r\n};\r\n\r\ntype TLocalisationReadyDetail = {\r\n  instance?: {\r\n    getLocale: (key: string, options?: Record<string, unknown>) => string;\r\n  };\r\n};\r\n\r\nconst isReadonlyField = (input: TValidationInput): boolean => {\r\n  return \"readOnly\" in input ? !!input.readOnly : false;\r\n};\r\n\r\nconst isDisabledOrReadonly = (input: TValidationInput): boolean => {\r\n  return !!input.disabled || isReadonlyField(input);\r\n};\r\n\r\nconst isLocalisationReadyEvent = (event: Event): event is CustomEvent<TLocalisationReadyDetail> => {\r\n  return event instanceof CustomEvent && typeof event.detail === \"object\" && event.detail !== null;\r\n};\r\n\r\n/**\r\n * Singleton. Плагин для валидации форм. Автоматически валидирует форму с атрибутом `data-js-form` и триггерит всплывающее событие. Работает как для `React` (триггер события), так и для статичной верстки (ручные манипуляции с DOM). Все исходные слушатели вешаются на документ.\r\n * @module FormValidation\r\n * @param options{Object=} параметры плагина\r\n * @param options.rules{Object=} объект дополнительных правил валидации\r\n * @param options.patterns{Object=} объект дополнительных паттернов валидации\r\n * @param options.ns{String=} неймспейс локалей\r\n * @example\r\n * // <form data-js-form='{ isLiveValidation: false }'>\r\n * //  <input data-js-input-required=\"\"> <!-- по умолчанию проверка на length -->\r\n * //  <input data-js-input-required=\"email\"> <!-- собственный тип валидации, описанный в rules -->\r\n * // </form>\r\n */\r\nexport class FormValidation {\r\n\r\n  static #instance: FormValidation | null = null;\r\n\r\n  /**\r\n   * Причины результата валидации\r\n   */\r\n  static reasons: Record<TValidationReason, TValidationReason> = {\r\n    valid: \"valid\",\r\n    invalid: \"invalid\",\r\n    empty: \"empty\",\r\n  };\r\n\r\n  /**\r\n   * Паттерны валидации\r\n   */\r\n  static patterns = {\r\n    // eslint-disable-next-line security/detect-unsafe-regex\r\n    email: /^(([^<>()\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/,\r\n    // eslint-disable-next-line security/detect-unsafe-regex\r\n    phone: /^(\\+{0,})(\\d{0,})([(]{1}\\d{1,3}[)]{0,}){0,}(\\s?\\d+|\\+\\d{2,3}\\s{1}\\d+|\\d+){1}[\\s|-]?\\d+([\\s|-]?\\d+){1,2}(\\s){0,}$/,\r\n  };\r\n\r\n  /**\r\n   * Карта валидаторов (для расширения исп. appendValidationRules)\r\n   * @type {MapConstructor}\r\n   */\r\n  static rules = getMapFromObj<string, TValidationRule>({\r\n    \"dateRange\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidDateRange(input as HTMLInputElement),\r\n      errorKeys: constants.defaultErrorsKeys,\r\n    },\r\n    \"date\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidDate(input as HTMLInputElement),\r\n      errorKeys: constants.defaultErrorsKeys,\r\n    },\r\n    \"email\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidEmail(input as HTMLInputElement),\r\n      errorKeys: { ...constants.defaultErrorsKeys, invalid: \"invalidEmail\" },\r\n    },\r\n    \"phone\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidPhone(input as HTMLInputElement), errorKeys: constants.defaultErrorsKeys,\r\n    },\r\n    \"checkbox\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidCheckbox(input as HTMLInputElement),\r\n      errorKeys: { empty: false, valid: false, invalid: \"invalidCheckbox\" },\r\n    },\r\n    \"radio\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidRadio(input as HTMLInputElement),\r\n      errorKeys: { empty: false, valid: false, invalid: \"invalidRadio\" },\r\n    },\r\n    \"file\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidFile(input as HTMLInputElement),\r\n      errorKeys: { empty: false, invalid: \"invalidFile\", valid: false },\r\n    },\r\n    \"greCaptcha\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidGreCaptcha(input as HTMLTextAreaElement), errorKeys: { empty: false, invalid: false, valid: false },\r\n    },\r\n    \"select\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidSelect(input as HTMLSelectElement), errorKeys: constants.defaultErrorsKeys,\r\n    },\r\n    \"\": {\r\n      fn: (input: TValidationInput) => FormValidation.isValidText(input as HTMLInputElement | HTMLTextAreaElement), errorKeys: constants.defaultErrorsKeys,\r\n    },\r\n  });\r\n\r\n  /**\r\n   * Добавляет новые правила валидации\r\n   * @param rules{Object}\r\n   */\r\n  static appendValidationRules(rules: Record<string, TValidationRule> = {}) {\r\n    Object.entries(rules).forEach(([ name = \"\", rule ]) => {\r\n      if (typeof name === \"string\" && typeof rule === \"object\" && rule && typeof rule.fn === \"function\" && typeof rule.errorKeys === \"object\") {\r\n        FormValidation.rules.set(name, rule);\r\n      } else {\r\n        console.error(`[FormValidation] Can't append new validation rule \"${name}\". Use this format: { rule: { fn, errorKeys } } `);\r\n      }\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Добавляет новый паттерн для масок\r\n   * @param patterns{Object=} паттерны\r\n   */\r\n  static appendPatterns(patterns: Record<string, RegExp>) {\r\n    Object.entries(patterns).forEach(([ name, regExp ]) => {\r\n      (FormValidation.patterns as Record<string, RegExp>)[name] = regExp;\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Неймспейс для локалей\r\n   * @private\r\n   */\r\n  static #ns = \"forms.\";\r\n\r\n  /**\r\n   * Селектор обычных полей, которые являются невалидными, но стали необязательными\r\n   * @type {string}\r\n   */\r\n  static #prevInvalidInputSelector = FormValidation.#getModifySelector(selectors.inputs, (selector) => `${selector}.${constants.stateClasses.invalid}:not(${selectors.formInput}, required)`);\r\n\r\n  /**\r\n   * Селектор специальных полей (выпадающие списки и календари), которые являются невалидными, но стали необязательными\r\n   * @type {string}\r\n   */\r\n  static #prevInvalidSpecialSelector = FormValidation.#getModifySelector(selectors.controlledInput, (selector) => `${selector}:not(${selectors.formInput}, required)`);\r\n\r\n  constructor(options: TValidationOptions = {}) {\r\n    const { rules = {}, patterns = {}, ns = FormValidation.#ns } = options;\r\n\r\n    FormValidation.#ns = ns;\r\n    FormValidation.appendValidationRules(rules);\r\n    if (patterns && Object.keys(patterns).length > 0) {\r\n      FormValidation.appendPatterns(patterns);\r\n    }\r\n\r\n    if (FormValidation.#instance) {\r\n      return FormValidation.#instance;\r\n    }\r\n\r\n    this.#bindEvents();\r\n    FormValidation.#instance = this;\r\n  }\r\n\r\n  #bindEvents() {\r\n    getDocument().addEventListener(\"reset\", (e: Event) => this.#handleReset(e));\r\n    getDocument().addEventListener(\"submit\", (e: Event) => this.#handleSubmit(e));\r\n    getDocument().addEventListener(\"change\", (e: Event) => this.#handleChange(e), true);\r\n    getDocument().addEventListener(\"blur\", (e: Event) => this.#handleInputBlur(e), true);\r\n    getDocument().addEventListener(\"keydown\", (e: Event) => this.#handleKeyDown(e), true);\r\n  }\r\n\r\n  static #isInputNeedBubble(input: TValidationInput) {\r\n    const attr = \"data-js-input-validation-bubble\";\r\n    return input.hasAttribute(attr) ? input.getAttribute(attr) === \"true\" : false;\r\n  }\r\n\r\n  #handleChange(e: Event) {\r\n    const { target, detail } = e as CustomEvent<{\r\n      container: HTMLElement | null;\r\n    }>;\r\n    if (\r\n      target instanceof HTMLInputElement\r\n      && target.matches(selectors.formInput)\r\n      && (target.type === \"radio\" || target.type === \"checkbox\")\r\n    ) {\r\n      if (FormValidation.isInputRequired(target)) { // если поле имеет валидацию\r\n        this.#liveValidate(target, {\r\n          container: detail?.container ?? null,\r\n        });\r\n      }\r\n    }\r\n  }\r\n\r\n  #handleKeyDown(e: Event) {\r\n    const { target, key } = e as KeyboardEvent & { target: Element; };\r\n    const form: IFormExtendedCfg[\"form\"] | null = target.closest(selectors.form);\r\n    if (key === \"Enter\" && !!form && !target.matches(\"textarea\")) {\r\n      const cfg = _getFormExtendedCfg(form);\r\n      if (cfg.isPreventSubmitByEnter) {\r\n        e.preventDefault();\r\n      }\r\n    }\r\n  }\r\n\r\n  #handleReset(e: Event) {\r\n    const { target } = e;\r\n    if (!!target && (target as Element).matches(selectors.form)) {\r\n      getUserControlledFields(target as HTMLFormElement)\r\n        .forEach((node) => {\r\n          bubble(node, \"reset\", {\r\n            form: target,\r\n          }, { bubbles: false });\r\n          // Если поле обязательно, то очистка результата валидации\r\n          const isRequired = FormValidation.isInputRequired(node as TValidationInput);\r\n          if (isRequired) {\r\n            FormValidation.isInputValid(node as TValidationInput, {\r\n              isBubble: _isReactNode(target as Element) || FormValidation.#isInputNeedBubble(node as TValidationInput),\r\n              getCustomValidityFn: () => ({\r\n                isValid: true,\r\n                reason: FormValidation.reasons.valid,\r\n              }),\r\n            });\r\n          }\r\n        });\r\n    }\r\n  }\r\n\r\n  #handleSubmit(e: Event) {\r\n    const { target } = e;\r\n    if (!!target && (target as Element).matches(selectors.form)) {\r\n      e.preventDefault();\r\n      const { isIgnoreValidation } = _getFormExtendedCfg(target as IFormExtendedCfg[\"form\"]);\r\n      if (!isIgnoreValidation) {\r\n        FormValidation.isValidForm(target as HTMLFormElement);\r\n      }\r\n      return false;\r\n    }\r\n  }\r\n\r\n  #liveValidate(input: TValidationInput, params: Partial<TValidateInputCfg> = {}) {\r\n    const form = getInputForm(input);\r\n    if (form && form.matches(selectors.form) && _getFormExtendedCfg(form as IFormExtendedCfg[\"form\"]).isLiveValidation) {\r\n      FormValidation.isInputValid(input, {\r\n        isBubble: _isReactNode(form),\r\n        ...params,\r\n      });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Обработчик события `blur` на документе\r\n   * @private\r\n   */\r\n  #handleInputBlur(e: Event) {\r\n    const { target } = e as FocusEvent & { target: Element; detail?: { container?: HTMLElement; }; };\r\n    const detail = (e as FocusEvent & { detail?: { container?: HTMLElement; }; }).detail;\r\n    if (target.nodeType === 1 && target.matches(selectors.inputs)) { // только поля\r\n      const container = detail?.container ?? null;\r\n      const parentContainer = target.parentElement;\r\n      if (!parentContainer) {\r\n        return;\r\n      }\r\n      const nearbyInput = parentContainer.querySelector<TValidationInput>(selectors.inputs); // поле с валидацией может быть рядом\r\n      if (FormValidation.isInputRequired(target as TValidationInput)) { // если поле имеет валидацию\r\n        this.#liveValidate(target as TValidationInput, {\r\n          container,\r\n        });\r\n      } else if (!!nearbyInput && FormValidation.isInputRequired(nearbyInput)) { // если поле рядом имеет валидацию\r\n        this.#liveValidate(nearbyInput, {\r\n          container: container || parentContainer,\r\n        });\r\n      } else if (target.matches(FormValidation.#prevInvalidInputSelector) || target.matches(FormValidation.#prevInvalidSpecialSelector)) { // если поле имело валидацию\r\n        this.#liveValidate(target as TValidationInput, {\r\n          container,\r\n          getCustomValidityFn: () => ({\r\n            isValid: true,\r\n            reason: FormValidation.reasons.valid,\r\n          }),\r\n        });\r\n      } else if (!!nearbyInput &&\r\n        (nearbyInput.matches(FormValidation.#prevInvalidInputSelector) || nearbyInput.matches(FormValidation.#prevInvalidSpecialSelector))\r\n      ) { // если поле рядом имело валидацию\r\n        this.#liveValidate(nearbyInput, {\r\n          container: container || parentContainer,\r\n          getCustomValidityFn: () => ({\r\n            isValid: true,\r\n            reason: FormValidation.reasons.valid,\r\n          }),\r\n        });\r\n      }\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Получает модифицированный селектор элементов\r\n   * @private\r\n   * @param selector{String=}\r\n   * @param getSelector{Function=}\r\n   * @returns {string}\r\n   */\r\n  static #getModifySelector(selector = \"\", getSelector = (str: string) => str) {\r\n    return selector.split(\",\")\r\n      .map((str) => {\r\n        const selector = str.trim();\r\n        return getSelector(selector);\r\n      })\r\n      .join(\", \");\r\n  }\r\n\r\n  /**\r\n   * Прокручивает к блоку указанного поля\r\n   * @param input{HTMLInputElement|HTMLTextAreaElement|HTMLSelectElement}\r\n   */\r\n  static scrollToField(input: TValidationInput) {\r\n    if (input) {\r\n      const block = input.closest(selectors.formBlock);\r\n      if (block) {\r\n        wait(300)\r\n          .finally(() => {\r\n            block.scrollIntoView({\r\n              block: \"start\",\r\n              behavior: \"smooth\",\r\n            });\r\n          });\r\n      }\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Проверят, валидна ли форма\r\n   * @param form{HTMLFormElement|Element|HTMLElement|Node} форма либо иной HTML-элемент\r\n   * @param params{Object=} дополнительные настройки\r\n   * @param params.inputs{NodeList|Array|HTMLCollection=} собственный список полей для валидации\r\n   * @param params.isIncludeDisabled{Boolean=} включение в валидацию полей с атрибутами disabled и readonly\r\n   * @param params.isBubble{Boolean=} всплытие события о валидации\r\n   * @param params.isSilent{Boolean=} включение \"тихой\" валидации без визуальных изменений\r\n   * @param params.ns{String=} namespace для локали\r\n   * @returns {boolean} возвращает результат валидации\r\n   */\r\n  static isValidForm(form: HTMLFormElement, params: TValidateCfg = {}) {\r\n\r\n    const {\r\n      inputs,\r\n      isIncludeDisabled = false,\r\n      isBubble = true,\r\n      isSilent = false,\r\n      isScroll = _getFormExtendedCfg(form as IFormExtendedCfg[\"form\"]).isScrollToFirstInvalidInput,\r\n      ns = FormValidation.#ns,\r\n    } = params;\r\n\r\n    // Пользователь передал собственные поля\r\n    const isCustomInputs = Array.isArray(inputs);\r\n\r\n    // Получение пользовательских полей\r\n    const getCustomInputs = () => isCustomInputs\r\n      ? (inputs || []).filter((input) => isIncludeDisabled || !isDisabledOrReadonly(input))\r\n      : [];\r\n\r\n    // Массив полей для валидации\r\n    const inputsToValidate: TValidationInput[] = isCustomInputs ? getCustomInputs() : FormValidation.getInputsToValidate(form, isIncludeDisabled);\r\n\r\n    if (!isSilent) {\r\n\r\n      // Дополнительные поля, которые являются невалидными, но стали необязательными\r\n      const prevInvalidInputs: TValidationInput[] = isCustomInputs\r\n        ? []\r\n        : FormValidation.getInputsToValidate(form, isIncludeDisabled, `${FormValidation.#prevInvalidInputSelector}, ${FormValidation.#prevInvalidSpecialSelector}`);\r\n\r\n      if (prevInvalidInputs.length) {\r\n        console.debug(`[Forms] Found inputs with previously required state:`, prevInvalidInputs);\r\n      }\r\n\r\n      [ ...inputsToValidate, ...prevInvalidInputs ]\r\n        .forEach((input) => FormValidation.isInputValid(input, {\r\n          ns,\r\n          getCustomValidityFn: prevInvalidInputs.includes(input) ? () => ({\r\n            isValid: true,\r\n            reason: FormValidation.reasons.valid,\r\n          }) : undefined,\r\n          isBubble: FormValidation.#isInputNeedBubble(input) || _isReactNode(form),\r\n        }));\r\n    }\r\n\r\n    // Валидна ли форма?\r\n    const isValid = inputsToValidate.every((input) => FormValidation.isFieldValid(input));\r\n\r\n    // Информация о полях\r\n    const data = inputsToValidate\r\n      .map((input) => ({\r\n        input,\r\n        isValid: FormValidation.isFieldValid(input),\r\n        type: FormValidation.#getInputValidationType(input) || \"\",\r\n      }));\r\n\r\n    // Скролл к некорректным полям\r\n    if (isScroll && !isValid) {\r\n      const firstInvalidData = data.find(({ isValid }) => !isValid);\r\n      if (firstInvalidData) {\r\n        FormValidation.scrollToField(firstInvalidData.input);\r\n      }\r\n    }\r\n\r\n    console.debug(`[Forms] Validation result: \"${isValid}\" `, form, data);\r\n\r\n    if (isBubble) {\r\n      const { formValid, formInvalid } = constants.formBubbles;\r\n      bubble(form, isValid ? formValid : formInvalid, { isValid, inputs: inputsToValidate });\r\n    }\r\n\r\n    return isValid;\r\n  }\r\n\r\n  /**\r\n   * Получает список полей для валидации внутри формы\r\n   * @param form{HTMLFormElement|HTMLElement|Node} форма\r\n   * @param isIncludeDisabled{Boolean=} включать в проверку поля с disabled и readonly\r\n   * @param selector{String=} селектор выбора полей\r\n   * @returns {Array} возвращает массив полей\r\n   */\r\n  static getInputsToValidate(form: HTMLFormElement | HTMLElement, isIncludeDisabled = false, selector = `${selectors.formInput}, ${selectors.greCaptcha}`): TValidationInput[] {\r\n\r\n    const { validateOnlySelector, id } = _getFormExtendedCfg(form as IFormExtendedCfg[\"form\"]);\r\n\r\n    // Контекст валидации\r\n    const getValidationCtxEl = () => {\r\n      if (!!validateOnlySelector && typeof validateOnlySelector === \"string\") {\r\n        if (isSelectorValid(validateOnlySelector)) {\r\n          const el = form.querySelector(validateOnlySelector);\r\n          if (el) {\r\n            return el;\r\n          } else {\r\n            console.warn(`\"[FormValidation] Selector of \"validateOnlySelector\" (\"${validateOnlySelector}\") can't find this node, use form instead`);\r\n            return form;\r\n          }\r\n        } else {\r\n          console.warn(`\"[FormValidation] Selector of \"validateOnlySelector\" (\"${validateOnlySelector}\") is invalid, use form instead`);\r\n          return form;\r\n        }\r\n      } else {\r\n        return form;\r\n      }\r\n    };\r\n    const validateEl = getValidationCtxEl();\r\n\r\n    // Поля внутри контекста валидации\r\n    const formInputs = [ ...validateEl.querySelectorAll<TValidationInput>(selector) ];\r\n\r\n    // Селектор для полей вне формы\r\n    const outFormInputsSelector = FormValidation.#getModifySelector(selector, (selector) => `${selector}[form=\"${id}\"]`);\r\n\r\n    // Поля вне формы с ID данной формы\r\n    const outFormInputs: TValidationInput[] = id ? [ ...getDocument().querySelectorAll(outFormInputsSelector) ] : [];\r\n\r\n    // Фильтрация полученных полей\r\n    return formInputs\r\n      .concat(outFormInputs)\r\n      .filter((input) => isIncludeDisabled || !isDisabledOrReadonly(input));\r\n  }\r\n\r\n  /**\r\n   * Получает статус поля как обязательного\r\n   * @param input{HTMLInputElement|HTMLTextAreaElement} поле\r\n   * @returns {boolean}\r\n   */\r\n  static isInputRequired(input: TValidationInput) {\r\n    return input.required || input.matches(selectors.formInput) && input.getAttribute(getAttr(selectors.formInput)) !== \"false\";\r\n  }\r\n\r\n  /**\r\n   * Получает тип валидации поля\r\n   * @private\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @returns {String}\r\n   */\r\n  static #getInputValidationType(input: TValidationInput) {\r\n\r\n    // Тип валидации по умолчанию\r\n    const defaultType = \"\";\r\n\r\n    // Название атрибута валидации\r\n    const attrName = getAttr(selectors.formInput);\r\n\r\n    // Заданный пользователем атрибут\r\n    const attr = input.hasAttribute(attrName) ? input.getAttribute(getAttr(selectors.formInput)) || defaultType : defaultType;\r\n\r\n    // Если атрибут не указан\r\n    const isEmptyAttr = attr.trim() === defaultType || attr === \"true\";\r\n\r\n    switch (true) {\r\n      // Google Captcha, особый тип валидации\r\n      case input.matches(selectors.greCaptcha):\r\n        return \"greCaptcha\";\r\n      // Не указан пользовательский тип, но поле обязательно и специфично\r\n      case isEmptyAttr && [ \"checkbox\", \"radio\", \"file\" ].includes(input.type):\r\n        return input.type;\r\n      // Явно пользовательский тип валидации\r\n      case !isEmptyAttr:\r\n        return attr;\r\n      // Валидация по умолчанию на пустоту строки\r\n      default:\r\n        return defaultType;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Получает метод валидации для поля\r\n   * @private\r\n   * @param validationType{String=}\r\n   * @returns {Object}\r\n   */\r\n  static #getValidationRuleForType(validationType = \"\") {\r\n    const defaultRule = FormValidation.rules.get(\"\");\r\n    if (FormValidation.rules.has(validationType)) {\r\n      return FormValidation.rules.get(validationType) || defaultRule || {\r\n        fn: () => true,\r\n        errorKeys: constants.defaultErrorsKeys,\r\n      };\r\n    }\r\n    return defaultRule || {\r\n      fn: () => true,\r\n      errorKeys: constants.defaultErrorsKeys,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Возвращает результат проверки поля без изменений в интерфейсе\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @param customType{String=} желаемый тип валидации\r\n   * @param isDetailResult{Boolean=} детальный отчет о валидации\r\n   * @returns {{reason: (string), isValid: *}|*}\r\n   */\r\n  static isFieldValid(input: TValidationInput, customType = \"\", isDetailResult = false) {\r\n\r\n    // Тип валидации поля\r\n    const validationType = customType || FormValidation.#getInputValidationType(input) || \"\";\r\n\r\n    // Правило валидации поля\r\n    const validationRule = FormValidation.#getValidationRuleForType(validationType);\r\n\r\n    // Результат валидации поля\r\n    const isValid = validationRule.fn(input);\r\n\r\n    if (isDetailResult) {\r\n      const getReason = () => {\r\n        switch (true) {\r\n          // поле валидно\r\n          case isValid:\r\n            return FormValidation.reasons.valid;\r\n          // особые типы валидации (у элементов с \"checked\" не может быть состояния empty)\r\n          case (validationType === \"checkbox\" || validationType === \"radio\") && !isValid:\r\n            return FormValidation.reasons.invalid;\r\n          // проверка на пустоту поля\r\n          case !FormValidation.isValidText(input):\r\n            return FormValidation.reasons.empty;\r\n          // поле заполнено неверно\r\n          default:\r\n            return FormValidation.reasons.invalid;\r\n        }\r\n      };\r\n      const reason = getReason();\r\n      return {\r\n        isValid,\r\n        reason,\r\n      };\r\n    } else {\r\n      return isValid;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Валидация Google Captcha\r\n   * @param textarea{HTMLTextAreaElement} скрытое textarea-поле GreCaptcha\r\n   * @returns {boolean}\r\n   */\r\n  static isValidGreCaptcha(textarea: HTMLTextAreaElement) {\r\n    return process.env.NODE_ENV === \"development\" ? true : string().min(1).isValidSync(textarea.value);\r\n  }\r\n\r\n  /**\r\n   * Валидация email\r\n   * @param input{HTMLInputElement} поле\r\n   * @returns {boolean}\r\n   */\r\n  static isValidEmail(input: HTMLInputElement) {\r\n    const { value } = input;\r\n    return string().matches(FormValidation.patterns.email).isValidSync(value);\r\n  }\r\n\r\n  /**\r\n   * Валидация номера телефона\r\n   * @param input{HTMLInputElement} поле\r\n   * @returns {boolean}\r\n   */\r\n  static isValidPhone(input: HTMLInputElement) {\r\n    const cleanPhone = input.value.replaceAll(/\\s/g, \"\");\r\n    return string()\r\n      .matches(FormValidation.patterns.phone)\r\n      .test(\"phone-length\", \"\", (value = \"\") => value.length === 16 || value.length === 11)\r\n      .isValidSync(cleanPhone);\r\n  }\r\n\r\n  /**\r\n   * Валидация radio input\r\n   * @param input{HTMLInputElement} поле типа \"radio\"\r\n   * @returns {boolean}\r\n   */\r\n  static isValidRadio(input: HTMLInputElement) {\r\n    const { name } = input;\r\n\r\n    return name ? [ ...getDocument().querySelectorAll(`[name=\"${name}\"]`) as NodeListOf<HTMLInputElement> ].some(({ checked }) => !!checked) : false;\r\n  }\r\n\r\n  /**\r\n   * Проверяет, валидный ли файл\r\n   * @param input{HTMLInputElement} поле типа \"file\"\r\n   * @returns {boolean}\r\n   */\r\n  static isValidFile(input: HTMLInputElement) {\r\n    return number().required().moreThan(0).isValidSync(input.files?.length);\r\n  }\r\n\r\n  /**\r\n   * @private\r\n   * @param value{String|Number}\r\n   * @returns {boolean}\r\n   */\r\n  static #isDateInstance(value: string | number) {\r\n    return !!value && new Date(value) instanceof Date && !isNaN(new Date(value).getTime());\r\n  }\r\n\r\n  /**\r\n   * Проверяет, валидный ли дата\r\n   * @param input{HTMLInputElement} поле типа \"text\"\r\n   * @returns {boolean}\r\n   */\r\n  static isValidDate(input: HTMLInputElement) {\r\n    const { value } = input;\r\n    if (!!value) { // не пустое\r\n      const num = Number(value);\r\n      if (isNaN(num)) { // возможно, это строка с датой\r\n        return FormValidation.#isDateInstance(value);\r\n      } else { // возможно, это штамп из getTime\r\n        return FormValidation.#isDateInstance(num);\r\n      }\r\n    } else {\r\n      return false;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Проверяет, валиден ли промежуток дат\r\n   * @param input{HTMLInputElement} поле типа \"text\"\r\n   * @returns {boolean}\r\n   */\r\n  static isValidDateRange(input: HTMLInputElement) {\r\n    const from = input.getAttribute(\"data-js-datepicker-from\");\r\n    const to = input.getAttribute(\"data-js-datepicker-to\");\r\n    return [ from, to ].every((value) => {\r\n      const num = Number(value);\r\n      if (isNaN(num)) { // возможно, это строка с датой\r\n        return FormValidation.#isDateInstance(value || \"\");\r\n      } else { // возможно, это штамп из getTime\r\n        return FormValidation.#isDateInstance(num);\r\n      }\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Проверяет, валидный ли checkbox\r\n   * @param input{HTMLInputElement} поле типа \"checkbox\"\r\n   * @returns {boolean}\r\n   */\r\n  static isValidCheckbox(input: HTMLInputElement) {\r\n    return boolean().oneOf([ true ]).isValidSync(input.checked);\r\n  }\r\n\r\n  /**\r\n   * Проверяет, заполнено ли текстовое поле\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @returns {boolean}\r\n   */\r\n  static isValidText(input: TValidationInput) {\r\n    const { value } = input;\r\n    return string().trim().min(1).isValidSync(value);\r\n  }\r\n\r\n  /**\r\n   * Проверяет, выбрана ли опция в селекте\r\n   * @param input{HTMLSelectElement} поле селекта\r\n   * @returns {boolean}\r\n   */\r\n  static isValidSelect(input: HTMLSelectElement) {\r\n    const { value } = input;\r\n    return string().trim().min(1).isValidSync(value);\r\n  }\r\n\r\n  /**\r\n   * Получает текст ошибки/успеха для поля, ожидая плагин локализации\r\n   * @private\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @param msgCodes{Object=} объект с сообщениями об ошибке или успехе\r\n   * @param reason{String=} тип ошибки или успешного сообщения\r\n   * @param ns{String=} неймспейс локали\r\n   * @returns {Promise}\r\n  */\r\n  static async #getInputMsg(input: TValidationInput, msgCodes: TValidationMsgCodes = {}, reason: TValidationReason = FormValidation.reasons.valid, ns = FormValidation.#ns) {\r\n    return new Promise<string>((resolve) => {\r\n      if (reason in msgCodes && msgCodes[reason] !== false) {\r\n        const key = `${ns}${msgCodes[reason]}`;\r\n        if (Localisation.instance && Localisation.isReady) {\r\n          resolve(String(Localisation.instance.getLocale(key, {})));\r\n        } else {\r\n          console.debug(`[Forms] Validation waiting for locales for key \"${key}\"...`);\r\n          getDocument().addEventListener(constants.localisationBubbles.localisationReady, (event: Event) => {\r\n            if (!isLocalisationReadyEvent(event)) {\r\n              return;\r\n            }\r\n            const { instance } = event.detail;\r\n            resolve(String(instance?.getLocale(key, {}) || \"\"));\r\n          }, { once: true });\r\n        }\r\n      } else {\r\n        resolve(\"\");\r\n      }\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Управление блоком ошибки/успеха у поля ввода\r\n   * @private\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @param msgCodes{Object=} объект с сообщениями об ошибке или успехе\r\n   * @param reason{String} тип ошибки или успешного сообщения\r\n   */\r\n  static async #setInputMsg(input: TValidationInput, msgCodes: TValidationMsgCodes = {}, reason: TValidationReason = FormValidation.reasons.valid) {\r\n    const msgBlock = FormValidation.#getInputMsgBlock(input);\r\n    if (msgBlock) {\r\n      const form = getInputForm(input);\r\n      if (form && reason === FormValidation.reasons.valid) {\r\n        return;\r\n      }\r\n      msgBlock.classList.add(constants.stateClasses.loading);\r\n      msgBlock.innerHTML = `<span class=\"form__msgLoader\" role=\"progressbar\"></span>`;\r\n      await FormValidation.#getInputMsg(input, msgCodes, reason)\r\n        .then((errText) => {\r\n          msgBlock.setAttribute(\"data-css-reason\", reason);\r\n          const msgText = getDocument().createElement(\"span\");\r\n          msgText.className = \"form__msgText\";\r\n          msgText.setAttribute(\"role\", \"tooltip\");\r\n          msgText.title = errText;\r\n          msgText.textContent = errText;\r\n          msgBlock.replaceChildren(msgText);\r\n          return Promise.resolve();\r\n        })\r\n        .catch(() => {\r\n          msgBlock.innerHTML = ``;\r\n        })\r\n        .finally(() => {\r\n          msgBlock.classList.remove(constants.stateClasses.loading);\r\n        });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Получает блок с сообщениями для поля\r\n   * @private\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @returns {Element|null}\r\n   */\r\n  static #getInputMsgBlock(input: TValidationInput) {\r\n    const defaultMsg = input.parentNode?.querySelector(selectors.formInputMsg) || input.closest(selectors.formBlock)?.querySelector(selectors.formInputMsg);\r\n    const name = input.name;\r\n    switch (true) {\r\n      case !!defaultMsg:\r\n        return defaultMsg;\r\n      case !!name.length:\r\n        return getDocument().querySelector(`[${getAttr(selectors.formInputMsg)}='${name}']`);\r\n      default:\r\n        return null;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Получает коды сообщений для поля\r\n   * @private\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   * @param validationType{String} тип валидации\r\n   * @returns {Object}\r\n   */\r\n  static #getInputErrorCodes(input: TValidationInput, validationType: string): TValidationMsgCodes {\r\n    validationType = validationType || FormValidation.#getInputValidationType(input) || \"\";\r\n    const errorAttr = getAttr(selectors.formInputMsg);\r\n    const errors = FormValidation.#getValidationRuleForType(validationType).errorKeys;\r\n    const getErrors = () => {\r\n      let customErrors = errors;\r\n      if (input.hasAttribute(errorAttr)) {\r\n        const attrValue = input.getAttribute(errorAttr);\r\n        if (!attrValue) {\r\n          return customErrors;\r\n        }\r\n        const custom: TValidationMsgCodes = getJSONFromStr<TValidationMsgCodes>(attrValue);\r\n        if (\r\n          !isObjEmpty(custom) &&\r\n          FormValidation.reasons.empty in custom &&\r\n          FormValidation.reasons.invalid in custom\r\n        ) {\r\n          customErrors = custom;\r\n        }\r\n      }\r\n      return customErrors;\r\n    };\r\n    return getErrors();\r\n  }\r\n\r\n  /**\r\n   * Очищает блок с сообщениями поля\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода\r\n   */\r\n  static clearInputMsgBlock(input: TValidationInput) {\r\n    const errorBlock = FormValidation.#getInputMsgBlock(input);\r\n    if (errorBlock) {\r\n      removeChildNodes(errorBlock);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Валидация поля ввода\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле ввода,\r\n   * @param params{Object=} параметры валидации\r\n   * @param params.isBubble{Boolean=} всплытие в результате валидации\r\n   * @param params.isSilent{Boolean=} \"тихая\" валидация без изменений в интерфейсе\r\n   * @param params.isDetailResult{Boolean=} вывод детального результата о валидации\r\n   * @param params.ns{String=} неймспейс для локали\r\n   * @param params.getCustomValidityFn{Function=} собственная логика валидации\r\n   * @returns {{reason: (string), isValid: *}|*}\r\n   */\r\n  static isInputValid(input: TValidationInput, params: TValidateInputCfg = {}) {\r\n\r\n    const {\r\n      isBubble = true,\r\n      isSilent = false,\r\n      isDetailResult = false,\r\n      getCustomValidityFn = undefined,\r\n      ns = FormValidation.#ns,\r\n      container = undefined,\r\n    } = params;\r\n\r\n    const validationType = FormValidation.#getInputValidationType(input) || \"\";\r\n\r\n    const msgCodes = FormValidation.#getInputErrorCodes(input, validationType);\r\n\r\n    const result = typeof getCustomValidityFn === \"function\"\r\n      ? getCustomValidityFn(input)\r\n      : FormValidation.isFieldValid(input, validationType || \"\", true) as TValidationResult;\r\n    const { isValid, reason } = result;\r\n\r\n    const updateValidationUI = () => FormValidation.setInputValidState(input, isValid, msgCodes, reason, container || null);\r\n\r\n    if (isBubble) {\r\n      const msgBlock = FormValidation.#getInputMsgBlock(input);\r\n      const msg = FormValidation.#getInputMsg(input, msgCodes, reason, ns);\r\n      const { inputValid, inputInvalid } = constants.formBubbles;\r\n      const detail: TValidationEvent[\"detail\"] = {\r\n        container: container || null,\r\n        reason,\r\n        isValid,\r\n        msgCodes,\r\n        msgBlock,\r\n        validationType,\r\n        input,\r\n        msg,\r\n        updateValidationUI,\r\n      };\r\n      [\r\n        { el: input },\r\n        {\r\n          el: msgBlock, params: { bubbles: false },\r\n        },\r\n      ]\r\n        .forEach(({ el, params = {} }) => {\r\n          if (el) {\r\n            bubble(el, isValid ? inputValid : inputInvalid, detail, params);\r\n          }\r\n        });\r\n    } else {\r\n      if (!isSilent) {\r\n        updateValidationUI();\r\n      }\r\n    }\r\n    return isDetailResult ? { isValid, reason } : isValid;\r\n  }\r\n\r\n  /**\r\n   * Добавление или удаление класса успешной или неуспешной валидации для элемента\r\n   * @private\r\n   * @param node{HTMLElement} элемент\r\n   * @param isValid{Boolean=} валидность\r\n   * @returns {boolean}\r\n   */\r\n  static #setValidClassToEl(node: Element, isValid = true) {\r\n    const { valid, invalid } = constants.stateClasses;\r\n    node.classList.remove(isValid ? invalid : valid);\r\n    node.classList.add(isValid ? valid : invalid);\r\n  }\r\n\r\n  /**\r\n   * Управление состоянием ошибки или корректности поля ввода\r\n   * @param input{HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} поле\r\n   * @param isValid{Boolean=} валидность поля\r\n   * @param msgCodes{Object=} объект с сообщениями об ошибке или успехе\r\n   * @param reason{String=} причина успешной или неуспешной валидации\r\n   * @param container{HTMLElement|null=} контейнер, для которого меняются классы\r\n   * @returns {boolean}\r\n   */\r\n  static setInputValidState(input: TValidationInput, isValid = true, msgCodes: TValidationMsgCodes = constants.defaultErrorsKeys, reason: TValidationReason = FormValidation.reasons.valid, container: HTMLElement | null = null) {\r\n    FormValidation.clearInputMsgBlock(input);\r\n    FormValidation.#setInputMsg(input, msgCodes, reason);\r\n\r\n    if (input.type === \"radio\" && !!input.name) { // радио-баттоны с одинаковым именем\r\n      const escapedName = input.name.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"\\\"\", \"\\\\\\\"\");\r\n      const radioButtons: NodeListOf<HTMLInputElement> = getDocument().querySelectorAll(`[name=\"${escapedName}\"]`);\r\n      radioButtons.forEach((radioInput) => {\r\n        FormValidation.#setValidClassToEl(radioInput, isValid);\r\n      });\r\n    } else {\r\n      FormValidation.#setValidClassToEl(container || input, isValid); // остальные поля\r\n    }\r\n  }\r\n\r\n}\r\n"],"names":["isReadonlyField","input","readOnly","isDisabledOrReadonly","disabled","isLocalisationReadyEvent","event","CustomEvent","detail","FormValidation","static","valid","invalid","empty","email","phone","getMapFromObj","dateRange","fn","isValidDateRange","errorKeys","constants","defaultErrorsKeys","date","isValidDate","isValidEmail","isValidPhone","checkbox","isValidCheckbox","radio","isValidRadio","file","isValidFile","greCaptcha","isValidGreCaptcha","select","isValidSelect","isValidText","appendValidationRules","rules","Object","entries","forEach","name","rule","set","console","error","appendPatterns","patterns","regExp","getModifySelector","selectors","inputs","selector","stateClasses","formInput","controlledInput","constructor","options","ns","keys","length","instance","this","bindEvents","getDocument","addEventListener","e","handleReset","handleSubmit","handleChange","handleInputBlur","handleKeyDown","isInputNeedBubble","attr","hasAttribute","getAttribute","target","HTMLInputElement","matches","type","isInputRequired","liveValidate","container","key","form","closest","cfg","_getFormExtendedCfg","isPreventSubmitByEnter","preventDefault","getUserControlledFields","node","bubble","bubbles","isRequired","isInputValid","isBubble","_isReactNode","getCustomValidityFn","isValid","reason","reasons","isIgnoreValidation","isValidForm","params","getInputForm","isLiveValidation","nodeType","parentContainer","parentElement","nearbyInput","querySelector","prevInvalidInputSelector","prevInvalidSpecialSelector","getSelector","str","split","map","trim","join","scrollToField","block","formBlock","wait","finally","scrollIntoView","behavior","isIncludeDisabled","isSilent","isScroll","isScrollToFirstInvalidInput","isCustomInputs","Array","isArray","getCustomInputs","filter","inputsToValidate","getInputsToValidate","prevInvalidInputs","debug","includes","undefined","every","isFieldValid","data","getInputValidationType","firstInvalidData","find","formValid","formInvalid","formBubbles","validateOnlySelector","id","getValidationCtxEl","isSelectorValid","el","warn","validateEl","formInputs","querySelectorAll","outFormInputsSelector","outFormInputs","concat","required","getAttr","defaultType","attrName","isEmptyAttr","getValidationRuleForType","validationType","defaultRule","get","has","customType","isDetailResult","validationRule","getReason","textarea","process","env","NODE_ENV","string","min","isValidSync","value","cleanPhone","replaceAll","test","some","checked","number","moreThan","files","isDateInstance","Date","isNaN","getTime","num","Number","from","to","boolean","oneOf","getInputMsg","msgCodes","Promise","resolve","Localisation","isReady","String","getLocale","localisationBubbles","localisationReady","once","setInputMsg","msgBlock","getInputMsgBlock","classList","add","loading","innerHTML","then","errText","setAttribute","msgText","createElement","className","title","textContent","replaceChildren","catch","remove","defaultMsg","parentNode","formInputMsg","getInputErrorCodes","errorAttr","errors","getErrors","customErrors","attrValue","custom","getJSONFromStr","isObjEmpty","clearInputMsgBlock","errorBlock","removeChildNodes","result","updateValidationUI","setInputValidState","msg","inputValid","inputInvalid","setValidClassToEl","escapedName","radioButtons","radioInput"],"mappings":"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"}