{"version":3,"file":"DatePickerCustomInput.mjs","sources":[""],"sourcesContent":["import { isValidDate } from \"@web3r/flowerkit/date\";\r\nimport type { ReactNode, FocusEvent, Ref } from \"react\";\r\nimport {\r\n  useEffect, useCallback, useRef, useState,\r\n} from \"react\";\r\nimport type { ReactMaskOpts } from \"react-imask\";\r\nimport { useIMask } from \"react-imask\";\r\nimport { useCN } from \"../../../utils/react/useCN\";\r\nimport { today } from \"../config/constants\";\r\nimport type { TDatePickerInputProps } from \"../config/types\";\r\n\r\n/**\r\n * Поле пользовательского ввода. Всегда имеет маску.\r\n * @returns {ReactNode}\r\n */\r\nexport const DatePickerCustomInput = ({\r\n  baseClass = \"formInput\",\r\n  extraClasses = {},\r\n  isDisabled = false,\r\n  children,\r\n  onBlur,\r\n  onClick,\r\n  onKeyDown,\r\n  date,\r\n  maxDate,\r\n  minDate,\r\n  pickerRef,\r\n  mask,\r\n  format,\r\n  handleChange,\r\n  isTime,\r\n  isRange,\r\n  isAutoFix,\r\n  timeIntervals,\r\n  placeholder,\r\n  ref,\r\n  ...rest\r\n}: TDatePickerInputProps): ReactNode => {\r\n\r\n  const getMaskValue = () => {\r\n    if (typeof mask === \"function\") {\r\n      const props = mask({\r\n        isRange,\r\n        isAutoFix,\r\n        format,\r\n        minDate,\r\n        maxDate,\r\n        isTime,\r\n        today,\r\n      });\r\n      return !!props ? props : null;\r\n    } else {\r\n      return null;\r\n    }\r\n  };\r\n\r\n  // Опции маски (может не быть, если range или маска убрана вручную)\r\n  const [ maskOptions, setMaskOptions ] = useState<ReactMaskOpts | null>(() => getMaskValue());\r\n  const prevMaskOptions = useRef<ReactMaskOpts | null>(maskOptions);\r\n\r\n  const {\r\n    setTypedValue,\r\n    setValue,\r\n    ref: maskRef,\r\n    maskRef: maskInstance,\r\n    value: maskValue,\r\n  } = useIMask(maskOptions || {}, {\r\n    onComplete: () => {\r\n      if (pickerRef.current) {\r\n        pickerRef.current.setOpen(false);\r\n      }\r\n    },\r\n    onAccept: (value, instance) => {\r\n      if (instance.masked && typeof instance.masked.parse === \"function\") {\r\n        const parsedDate = value ? instance.masked.parse(value, instance.masked) : undefined;\r\n        if (!!parsedDate && isValidDate(parsedDate) && !!pickerRef?.current?.calendar) {\r\n          const mm = parsedDate.getMonth();\r\n          pickerRef.current.calendar.changeMonth(mm);\r\n        }\r\n      }\r\n    },\r\n  });\r\n\r\n  const { getCN } = useCN(baseClass);\r\n\r\n  // Предыдущее значение\r\n  const prevDate = useRef(date);\r\n\r\n  // Сброс некорректно введенной даты\r\n  const handleBlur = useCallback((e: FocusEvent<HTMLInputElement>) => {\r\n    if (!!maskOptions) {\r\n\r\n      const masked = maskInstance.current?.masked;\r\n\r\n      // Проверка готовности маски\r\n      if (!!masked && typeof masked.parse === \"function\") {\r\n\r\n        // То, что ввёл пользователь\r\n        const currentValue = e.target.value;\r\n\r\n        // Парсинг данных из маски\r\n        const parsedDate = currentValue ? masked.parse(currentValue, masked) : undefined;\r\n\r\n        if (!!parsedDate && isValidDate(parsedDate)) { // дата пользователя валидна\r\n          const formattedValue = (date: Date) => {\r\n            return typeof masked.format === \"function\" ? masked.format(date as never, masked) : \"\";\r\n          };\r\n          switch (true) {\r\n            // пользователь ввел дату больше, чем нужно\r\n            case (parsedDate > maxDate!):\r\n              setValue(isAutoFix ? formattedValue(maxDate!) : \"\");\r\n              handleChange(isAutoFix ? maxDate : null, e);\r\n              console.debug(`[DatePicker] Parsed date \"${parsedDate}\" fixed to max \"${maxDate}\"`);\r\n              break;\r\n            // пользователь ввел дату меньше, чем нужно\r\n            case (parsedDate < minDate!):\r\n              setValue(isAutoFix ? formattedValue(minDate!) : \"\");\r\n              handleChange(isAutoFix ? minDate : null, e);\r\n              console.debug(`[DatePicker] Parsed date \"${parsedDate}\" fixed to min \"${minDate}\"`);\r\n              break;\r\n            default:\r\n              // пользователь ввёл корректную дату\r\n              if (isTime && Number.isFinite(timeIntervals)) { // дополнительная проверка на кратность минут, если `isTime`\r\n                const MM = parsedDate.getMinutes();\r\n                if (MM % timeIntervals!) {\r\n                  const roundedMM = Math.round(MM / timeIntervals!) * timeIntervals!;\r\n                  parsedDate.setMinutes(roundedMM);\r\n                  setValue(formattedValue(parsedDate));\r\n                  console.debug(`[DatePicker] Parsed date \"${parsedDate}\" fixed: corrected minutes \"${roundedMM}\"`);\r\n                }\r\n              }\r\n              handleChange(parsedDate, e);\r\n          }\r\n        } else { // дата пользователя невалидна\r\n          setValue(\"\");\r\n          setTypedValue(\"\");\r\n          handleChange(null, e);\r\n        }\r\n      }\r\n    }\r\n    if (typeof onBlur === \"function\") {\r\n      onBlur(e);\r\n    }\r\n  }, [ maskOptions, onBlur, maskInstance, maxDate, setValue, isAutoFix, handleChange, minDate, isTime, timeIntervals, setTypedValue ]);\r\n\r\n  useEffect(() => {\r\n    const updatedMask = getMaskValue();\r\n    if (updatedMask !== prevMaskOptions.current) {\r\n      setMaskOptions(updatedMask);\r\n      prevMaskOptions.current = updatedMask;\r\n    }\r\n  }, [ isRange, isAutoFix, format, minDate, maxDate, isTime ]);\r\n\r\n  useEffect(() => {\r\n    if (!!maskOptions) {\r\n      if (isValidDate(date)) { // валидная дата\r\n        const masked = maskInstance?.current?.masked;\r\n        if (!!masked && typeof masked?.format === \"function\") {\r\n          const formattedValue = masked.format(date as never, masked);\r\n          setValue(formattedValue);\r\n        }\r\n      } else if (prevDate.current !== date) { // сброс даты\r\n        setValue(\"\");\r\n        maskInstance.current!.value = \"\"; // обновление UI iMask\r\n      }\r\n      prevDate.current = date;\r\n    }\r\n  }, [ date ]);\r\n\r\n  const computedProps = {\r\n    onChange: () => {}, // prevent react warning\r\n    onBlur: handleBlur,\r\n    className: getCN(\"\", extraClasses),\r\n    disabled: isDisabled,\r\n    placeholder,\r\n    onClick,\r\n    onKeyDown,\r\n    value: !!maskOptions ? maskValue : rest.value, // conditional value\r\n    ref: (!!maskOptions ? maskRef : ref) as Ref<HTMLInputElement>, // conditional ref,\r\n    max: undefined,\r\n    min: undefined,\r\n    inputMode: \"numeric\" as const,\r\n  };\r\n\r\n  return (\r\n    <>\r\n      <input {...computedProps} />\r\n      {children}\r\n    </>\r\n  );\r\n\r\n};\r\n\r\n"],"names":["DatePickerCustomInput","baseClass","extraClasses","isDisabled","children","onBlur","onClick","onKeyDown","date","maxDate","minDate","pickerRef","mask","format","handleChange","isTime","isRange","isAutoFix","timeIntervals","placeholder","ref","rest","getMaskValue","props","today","maskOptions","setMaskOptions","useState","prevMaskOptions","useRef","setTypedValue","setValue","maskRef","maskInstance","value","maskValue","useIMask","onComplete","current","setOpen","onAccept","instance","masked","parse","parsedDate","undefined","isValidDate","calendar","mm","getMonth","changeMonth","getCN","useCN","prevDate","handleBlur","useCallback","e","currentValue","target","formattedValue","console","debug","Number","isFinite","MM","getMinutes","roundedMM","Math","round","setMinutes","useEffect","updatedMask","computedProps","onChange","className","disabled","max","min","inputMode","_jsxs","_Fragment","_jsx"],"mappings":"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"}