UNPKG

@kubit-ui-web/react-components

Version:

Kubit React Components is a customizable, accessible library of React web components, designed to enhance your application's user experience

364 lines 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useInputDate = void 0; const react_1 = require("react"); const useInput_1 = require("../../../hooks/useInput/useInput"); const provider_1 = require("../../../provider/utils/provider"); const formatDate_1 = require("../../../utils/date/formatDate"); const formatDateToNative_1 = require("../../../utils/syntheticComponents/syntheticDate/helper/formatDateToNative"); const syntheticDate_1 = require("../../../utils/syntheticComponents/syntheticDate/syntheticDate"); const useInternalValidations_1 = require("../../input/hooks/useInternalValidations"); const input_1 = require("../../input/types/input"); const internalErrors_1 = require("../../input/types/internalErrors"); const verifyDate_1 = require("../utils/verifyDate"); const useInputDate = ({ ref, errorExecution, internalErrorExecution, keyValidation, max, min, maxLength, minLength, maxDate = new Date(), mask, maskType, disabled, error, currentValue, today = '', type, truncate, informationAssociated, disabledCopyAndPaste, onWrapperBlur, onBlur, onChange, onFocus, onKeyDown, onError, onInternalErrors, onPaste, ...props }) => { // Ghost prototype const { setDate } = (0, react_1.useMemo)(() => { if (typeof window !== 'undefined' && typeof document !== 'undefined') { return (0, syntheticDate_1.syntheticDate)(props.name); } return { setDate: () => null }; }, []); // Auxiliar methods const buildRangeDates = (date) => { const orderDates = date.sort((a, b) => new Date(a).getTime() - new Date(b).getTime()); return { startDate: orderDates[0], endDate: orderDates[1], }; }; const getDate = (date) => { if (date) { const formatedDate = formatDate(date, props.format); return formatedDate; } return ''; }; const orderStringDates = (date) => { const isValidDate = (0, verifyDate_1.verifyDate)(props.format, date, props.minDate, maxDate, props.dateSeparator, props.hasRange, today); const datesFormatted = [ transformDate(date.split(' ')[0], props.format), transformDate(date.split(' ')[1], props.format), ]; return isValidDate ? [...datesFormatted].sort((a, b) => new Date(a).getTime() - new Date(b).getTime()) : date; }; // used when selecting date in calendar or transforming dates in internal validation // updates date and dateFormatted states // set the showcalendar state to false const handleChangeDate = (newDate, hasError = false) => { if (!hasError) { if (props.hasRange && newDate.length === 2) { props.onSelectedDateChange?.(buildRangeDates([newDate[0], newDate[1]])); setDateFormatted(newDate); if (newDate[1]) { setCalendarOpen(false); } } else { props.onSelectedDateChange?.(newDate[0]); setDateFormatted([newDate[0]]); setCalendarOpen(false); } props.onCalendarOpen?.(false); } onError?.(hasError); }; // validate formatted dates when date range const handleChangeInternalValidateDateRange = (dateRange) => { const isValidDateRange = (0, verifyDate_1.verifyDate)(props.format, dateRange, props.minDate, maxDate, props.dateSeparator, true, today); // Regex to split dates with dateSeparator ("to") const regexSplit = /[\sA-Za-z]+/; const dateRangeFormatted = dateRange.split(regexSplit); if (dateRangeFormatted && dateRangeFormatted?.length >= 2) { if (isValidDateRange) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE); } else { addInternalError(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE); } } handleChangeDate([ transformDate(dateRangeFormatted[0], props.format), transformDate(dateRangeFormatted[1], props.format), ], !isValidDateRange); }; // validate formatted dates when single date const handleChangeInternalValidateSingleDate = (date) => { const isValidDate = (0, verifyDate_1.verifyDate)(props.format, date, props.minDate, maxDate, props.dateSeparator, props.hasRange, today); if (isValidDate) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE); } else { addInternalError(internalErrors_1.InternalErrorType.INVALID_DATE); } handleChangeDate([transformDate(date, props.format)], !isValidDate); }; const createDateFormatted = (initialDate, initialSecondDate) => { if (initialDate) { if (initialSecondDate) { return [initialDate, initialSecondDate]; } return [initialDate]; } return []; }; // states, constants and refs const [calendarOpen, setCalendarOpen] = (0, react_1.useState)(false); const [dateFormatted, setDateFormatted] = (0, react_1.useState)(createDateFormatted(props.initialDate, props.initialSecondDate)); const firstRender = (0, react_1.useRef)(true); const { transformDate, formatDate } = (0, provider_1.useUtilsProvider)(); const { internalErrors, addInternalError, removeInternalError } = (0, useInternalValidations_1.useInternalValidations)(type, undefined, onInternalErrors); // Methods // Popover control calendar const handleOpenCalendar = (open) => { setCalendarOpen(open); props.onCalendarOpen?.(open); }; const handleClickInput = event => { if (calendarOpen) { setCalendarOpen(false); props.onCalendarOpen?.(false); } props.onClick?.(event); }; const onBlurDate = event => { if (event.currentTarget.contains(event.relatedTarget)) { return; } const inputValue = inputRef?.current?.value ?? ''; if (errorExecution === input_1.ERROR_EXECUTION.ON_BLUR) { if (props.hasRange) { handleChangeInternalValidateDateRange(inputValue); } else { handleChangeInternalValidateSingleDate(inputValue); } } const hasError = internalErrors.length > 0; props.onDateError?.(hasError); let adaptEvent; const dateValue = inputValue; if (props.hasRange) { const hasSeparator = props.dateSeparator && dateValue.includes(props.dateSeparator); const secondDateExists = dateValue.length > props.format.length; const dates = hasSeparator ? dateValue.split(props.dateSeparator) : dateValue.split(' '); const firstDate = (0, formatDateToNative_1.formatDateToNative)(dates[0].trim(), props.format, true); const secondDate = secondDateExists ? (0, formatDateToNative_1.formatDateToNative)(dates[1].trim(), props.format, true) : ''; const firstValueAsNumber = firstDate.length && (0, formatDate_1.formatDateToUTC)(firstDate).getTime(); const secondValueAsNumber = secondDate.length && (0, formatDate_1.formatDateToUTC)(secondDate).getTime(); const firstValueAsDate = firstDate.length && (0, formatDate_1.formatDateToUTC)(firstDate); const secondValueAsDate = secondDate.length && (0, formatDate_1.formatDateToUTC)(secondDate); adaptEvent = { target: { value: `${firstDate} ${secondDate}`, valueAsNumber: `${firstValueAsNumber} ${secondValueAsNumber}`.trim(), valueAsDate: `${firstValueAsDate} - ${secondValueAsDate}`, }, }; } else { adaptEvent = setDate(dateValue, props.format); } onWrapperBlur?.(adaptEvent); }; // validate formatted dates const handleChangeInternalValidate = event => { const dateValue = event?.target?.value; // reset the internal errors for new verify if (internalErrors.includes(internalErrors_1.InternalErrorType.INVALID_DATE)) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE); } else if (internalErrors.includes(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE)) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE); } // date range if (dateValue?.length === props.format?.length * 2 + 1) { if (errorExecution === input_1.ERROR_EXECUTION.ON_CHANGE) { handleChangeInternalValidateDateRange(dateValue); } const orderedRangeDates = orderStringDates(dateValue); // if the first date is invalid give an error const hasError = internalErrors.length > 0; // add ordered dates in ref value if (inputRef?.current) { inputRef.current.value = !hasError && typeof orderedRangeDates !== 'string' ? `${formatDate(orderedRangeDates[0], props.format)} ${formatDate(orderedRangeDates[1], props.format)}` : dateValue; } // add date separator in ref value inputRef?.current?.setRangeText(` ${props.dateSeparator}`, props.format.length, props.format.length, 'end'); // single date } else if (dateValue?.length === props.format?.length && errorExecution === input_1.ERROR_EXECUTION.ON_CHANGE) { handleChangeInternalValidateSingleDate(dateValue); } let adaptEvent; if (props.hasRange) { const hasSeparator = props.dateSeparator && dateValue.includes(props.dateSeparator); const secondDateExists = dateValue.length > props.format.length; const dates = hasSeparator ? dateValue.split(props.dateSeparator) : dateValue.split(' '); const firstDate = (0, formatDateToNative_1.formatDateToNative)(dates[0].trim(), props.format, true); const secondDate = secondDateExists ? (0, formatDateToNative_1.formatDateToNative)(dates[1].trim(), props.format, true) : ''; const firstValueAsNumber = firstDate.length && (0, formatDate_1.formatDateToUTC)(firstDate).getTime(); const secondValueAsNumber = secondDate.length && (0, formatDate_1.formatDateToUTC)(secondDate).getTime(); const firstValueAsDate = firstDate.length && (0, formatDate_1.formatDateToUTC)(firstDate); const secondValueAsDate = secondDate.length && (0, formatDate_1.formatDateToUTC)(secondDate); adaptEvent = { target: { value: `${firstDate} ${secondDate}`, valueAsNumber: `${firstValueAsNumber} ${secondValueAsNumber}`.trim(), valueAsDate: `${firstValueAsDate} - ${secondValueAsDate}`, }, }; } else { adaptEvent = setDate(dateValue, props.format); } onChange?.(adaptEvent); }; const handlePickCalendarDate = (newPickDate) => { // clean errors setted by internal validation, when date is selected from calendar if (internalErrors.includes(internalErrors_1.InternalErrorType.INVALID_DATE)) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE); } else if (internalErrors.includes(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE)) { removeInternalError(internalErrors_1.InternalErrorType.INVALID_DATE_RANGE); } const orderedDates = [...newPickDate].sort((a, b) => new Date(a).getTime() - new Date(b).getTime()); const formattedDates = orderedDates.map(date => formatDate(date, props.format)); const hasSecondaDate = formattedDates.length === 2; const dateValue = hasSecondaDate ? formattedDates.join(' ') : formattedDates[0]; handleChangeDate(newPickDate); if (props.hasRange) { handleSetValue(`${getDate(orderedDates[0])} ${getDate(orderedDates[1])}`); } else if (dateValue?.length === props.format?.length) { if (inputRef?.current) { // Inner input value should be set before the rerendering // This avoid calling onChange event when input.value is different from the current value when picking a date inputRef.current.value = dateValue; // When selecting a date from the calendar, set the cursor to the end of the input eventKeyPressRef.current = { key: '', cursor: { start: dateValue.length, end: dateValue.length, }, }; } handleSetValue(dateValue); } let adaptEvent; if (hasSecondaDate) { const firstNativeDate = (0, formatDateToNative_1.formatDateToNative)(getDate(orderedDates[0]), props.format, true); const secondNativeDate = (0, formatDateToNative_1.formatDateToNative)(getDate(orderedDates[1]), props.format, true); const firstValueAsNumber = (0, formatDate_1.formatDateToUTC)(orderedDates[0]).getTime(); const secondValueAsNumber = (0, formatDate_1.formatDateToUTC)(orderedDates[1]).getTime(); adaptEvent = { target: { value: `${firstNativeDate} ${secondNativeDate}`, valueAsNumber: `${firstValueAsNumber} ${secondValueAsNumber}`, valueAsDate: `${orderedDates[0]} - ${orderedDates[1]}`, }, }; } else { const dateSelected = getDate(orderedDates[0]); adaptEvent = setDate(dateSelected, props.format); } onChange?.(adaptEvent); }; (0, react_1.useEffect)(() => { // On close calendar input will recive focus automatically // Also avoid focus when rendering the component if (!calendarOpen && !firstRender.current) { inputRef?.current?.focus(); } firstRender.current = false; }, [calendarOpen]); const { value, state, eventKeyPressRef, inputRef, handleChangeInternal, handleBlurInternal, handleFocusInternal, handleKeyDownInternal, handleSetValue, handlePasteInternal, } = (0, useInput_1.useInput)({ ref, keyValidation, internalErrorExecution, max, min, maxLength, minLength, mask, maskType, disabled, error: error || internalErrors.length > 0, currentValue, type, truncate, informationAssociated, disabledCopyAndPaste, onBlur, onFocus, onKeyDown, onError, onInternalErrors, onChange: handleChangeInternalValidate, onPaste, }); // update initial dates when they have value (0, react_1.useEffect)(() => { setDateFormatted(createDateFormatted(props.initialDate && (0, formatDate_1.formatDateToUTC)(props.initialDate), props.initialSecondDate && (0, formatDate_1.formatDateToUTC)(props.initialSecondDate))); if (props.hasRange) { const newValue = props.initialDate || props.initialSecondDate ? `${getDate(props.initialDate)} ${props.dateSeparator} ${getDate(props.initialSecondDate)}` : ''; handleSetValue(newValue); } else { handleSetValue(getDate(props.initialDate)); } }, [props.initialDate, props.initialSecondDate]); (0, react_1.useEffect)(() => { if (String(value).length === props.format?.length * 2 + 1) { // to set date separator when date is selected from calendar inputRef?.current?.setRangeText(` ${props.dateSeparator}`, props.format.length, props.format.length, 'end'); if (inputRef?.current) { handleSetValue(inputRef?.current?.value); } } //Set "Today, " when today date is selected or typed on single date if (String(value) === formatDate(new Date(), props.format) && String(value)?.length === props.format?.length && !props.hasRange) { handleSetValue(`${today}${value}`); } }, [value]); return { dateFormatted, calendarOpen, handleClickInput, handlePickCalendarDate, handleOpenCalendar, handleChangeInternalValidate, value, state, inputRef, handleChangeInternal, handleBlurInternal, handleWrapperBlur: onBlurDate, handleFocusInternal, handleKeyDownInternal, handleSetValue, handlePasteInternal, }; }; exports.useInputDate = useInputDate; //# sourceMappingURL=useInputDate.js.map