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

287 lines 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.useInput = void 0; const react_1 = require("react"); const useInternalValidations_1 = require("../../components/input/hooks/useInternalValidations"); const input_1 = require("../../components/input/types/input"); const inputType_1 = require("../../components/input/types/inputType"); const formatNumber_1 = require("../../components/input/utils/formatNumber"); const state_utils_1 = require("../../components/input/utils/state.utils"); const truncatedValue_1 = require("../../components/inputCurrency/helpers/truncatedValue"); const keyboardKeys_1 = require("../../constants/keyboardKeys/keyboardKeys"); const mask_utility_1 = require("../../utils/maskUtility/mask.utility"); const validationsProvider_1 = require("../../provider/validations/validationsProvider"); const cursor_utility_1 = require("../../utils/cursorUtility/cursor.utility"); const keyboard_utility_1 = require("../../utils/keyboard/keyboard.utility"); const string_utility_1 = require("../../utils/stringUtility/string.utility"); const limitValue_1 = require("./helpers/limitValue"); const modifyInputNumberValue_1 = require("./helpers/modifyInputNumberValue"); const useInput = (props) => { const [value, setValue] = (0, react_1.useState)(props.currentValue || ''); const [focus, setFocus] = (0, react_1.useState)(false); const { validationValue } = (0, validationsProvider_1.useValidations)(); const { internalErrors, checkInternalValidations } = (0, useInternalValidations_1.useInternalValidations)(props.type, props.minLength, props.onInternalErrors); const handleSetValue = value => { setValue(value); }; const state = (0, react_1.useMemo)(() => (0, state_utils_1.getState)(value, focus, props.disabled, internalErrors.length > 0 || props.error, props.informationAssociated), [value, focus, props.disabled, internalErrors.length, props.error, props.informationAssociated]); const eventKeyPressRef = (0, react_1.useRef)(); const positionRef = (0, react_1.useRef)(0); const inputRef = (0, react_1.useRef)(); const pasteRef = (0, react_1.useRef)(false); // Return ref of the input element (0, react_1.useImperativeHandle)(props.ref, () => { return inputRef.current; }, []); const firstRender = (0, react_1.useRef)(true); (0, react_1.useEffect)(() => { if (props.currentValue !== undefined) { let newValue = props.currentValue; // format with formatNumber configuration if (firstRender.current && props.formatNumber && !focus) { // add thousand separator to the value newValue = addThousandSeparator(String(props.currentValue), props.formatNumber); } // limit or truncate the value controlValue(newValue); } else { handleSetValue(''); } firstRender.current = false; }, [props.currentValue]); (0, react_1.useEffect)(() => { positionRef.current = (0, string_utility_1.maxCountBetweenChars)('#', props.mask) + 1; }, []); (0, react_1.useEffect)(() => { //avoid change value on input number using wheel mouse const input = inputRef.current; if (props.disabledWheelMouse && input) { const handleWheel = e => { e.preventDefault(); }; input.addEventListener('wheel', handleWheel); return () => { input.removeEventListener('wheel', handleWheel); }; } return undefined; }, []); (0, react_1.useEffect)(() => { // prevent the behaviour, when the value is changed by paste method if (pasteRef.current) { pasteRef.current = false; return; } if (eventKeyPressRef.current && props.mask && inputRef?.current && value) { const popoverElements = document.querySelectorAll('[data-calendar], [data-input-dropdown-list], [data-input-search-list]'); const { start, end } = eventKeyPressRef.current.cursor; // if multiple digits are selected, recovery the selected area const area = Math.abs(start - end); // this the mask representation of the selected area const selected = props.mask.slice(start, end); // match the mask representation with the mask character const maskChart = selected.match(/#/g); // calculate the difference between the selected area and the mask representation const diffStart = maskChart ? Math.abs(maskChart.length - area) : 0; const diffEnd = maskChart ? maskChart.length : 0; const position = (0, cursor_utility_1.getPosition)(eventKeyPressRef.current.key, value, eventKeyPressRef.current.cursor, positionRef.current); if (popoverElements.length !== 0) { inputRef.current.focus(); } inputRef.current.setSelectionRange(start + diffStart + position, end - diffEnd + position); } }, [value]); const truncateFloatValue = value => { if (value === '') { return value; } const hasMark = value.match(/[^a-zA-Z0-9]/g); const isLastCharAMark = hasMark && props.maxLength && value.length >= props.maxLength && value[props.maxLength - 1] === hasMark[0]; return isLastCharAMark && props.type === inputType_1.InputTypeType.NUMBER ? value.replace(hasMark[0], '') : value; }; const controlValue = value => { // control character limit const limitedValue = value && (0, limitValue_1.limitValue)(value, props.min, props.max, props.maxLength); // truncate the value with maximun of decimals const truncateValue = props.truncate && props.maxDecimals !== null && props.maxDecimals !== undefined ? (0, truncatedValue_1.truncatedValue)(String(limitedValue), props.maxDecimals, props.locale || props.formatNumber?.locale) : String(limitedValue); const valueTruncated = truncateFloatValue(truncateValue); handleSetValue(valueTruncated); return valueTruncated; }; // add thousand separator to the value const addThousandSeparator = (value, format) => { if ((0, formatNumber_1.checkValidFormattedNumber)(value, props.locale || format.locale)) { // remove existing thousand separator const newValue = (0, formatNumber_1.removeThousandSeparator)(value, props.locale || format.locale); // format value const formattedValue = (0, formatNumber_1.formatNumber)(Number(newValue), format, props.locale || format.locale); return formattedValue; } return value; }; const handleChangeInternal = event => { let eventValue = event.target.value; // format value with the mask if (props.maskType) { let newMaskedValue = (0, mask_utility_1.cleanInputValue)(eventValue, props.maskType); if (props.mask) { newMaskedValue = (0, mask_utility_1.formatMask)(newMaskedValue, props.mask); } eventValue = newMaskedValue; } else if (props.regex) { const newMaskedValue = (0, mask_utility_1.matchInputValue)(String(value), eventValue, props.regex); eventValue = newMaskedValue; } // key validation if (props.errorExecution === input_1.ERROR_EXECUTION.ON_CHANGE && props.keyValidation) { props.onError?.(!validationValue(props.keyValidation, eventValue)); } // limit or truncate the value const valueControlled = controlValue(eventValue); // check internal validations if (props.type !== inputType_1.InputTypeType.DATE && (props.internalErrorExecution === input_1.INTERNAL_ERROR_EXECUTION.ON_CHANGE || props.internalErrorExecution === input_1.INTERNAL_ERROR_EXECUTION.ON_CHANGE_ON_BLUR)) { checkInternalValidations(eventValue); } if ((0, modifyInputNumberValue_1.modifyInputNumberValue)({ value: eventValue, min: props.min, max: props.max, maxLength: props.maxLength, }) || props.type !== inputType_1.InputTypeType.NUMBER) { event.target.value = valueControlled; } // value = previous value // valueControlled = current value if (value === valueControlled) { return; } props.onChange?.(event); }; const handleBlurInternal = event => { if (props.internalErrorExecution === input_1.INTERNAL_ERROR_EXECUTION.ON_BLUR || props.internalErrorExecution === input_1.INTERNAL_ERROR_EXECUTION.ON_CHANGE_ON_BLUR) { checkInternalValidations(event.target.value); } if (props.formatNumber) { // add thousand separator to the value event.target.value = addThousandSeparator(event.target.value, props.formatNumber); handleSetValue(event.target.value); } props.onBlur?.(event); if (props.errorExecution === input_1.ERROR_EXECUTION.ON_BLUR && props.keyValidation) { props.onError?.(!validationValue(props.keyValidation, event.target.value)); } setFocus(false); }; const handleFocusInternal = event => { if (props.formatNumber) { // remove thousand separator to the value event.target.value = (0, formatNumber_1.removeThousandSeparator)(event.target.value, props.locale || props.formatNumber?.locale, false); handleSetValue(event.target.value); } // transform the string value to a number format with dot as decimal separator to avoid errors const decimalNumber = (0, formatNumber_1.convertDecimalSeparator)(event.target.value, (0, formatNumber_1.getDecimalSeparator)(props.locale || props.formatNumber?.locale)); if (!isNaN(parseFloat(decimalNumber)) && isFinite(parseFloat(decimalNumber))) { event.target.value = decimalNumber; } props.onFocus?.(event); setFocus(true); }; const handleKeyDownInternal = event => { if (props.ignoreKeys?.includes(event.key)) { event.preventDefault(); } if (props.type === inputType_1.InputTypeType.NUMBER && ((0, keyboard_utility_1.isArrowUpPressed)(event.key) || (0, keyboard_utility_1.isArrowDownPressed)(event.key))) { event.preventDefault(); } const { key, currentTarget: { selectionStart, selectionEnd }, } = event; let start = selectionStart ?? 0; let end = selectionEnd ?? 0; const isSelected = Math.abs(start - end) > 0; // Check if the input has a mask if (props.mask && inputRef.current && start !== null && end !== null) { // Check if the key pressed is "Backspace" or "Delete" // Check if the character at the cursor position is a mask character if (key === keyboardKeys_1.BACKSPACE.key && props.mask[start - 1] && props.mask[start - 1] !== '#') { if (!isSelected) { let count = 1; // Check if the character at the cursor position is a mask character for (let index = start - 1; index >= 0; index--) { if (props.mask[index] === '#') { count = start - 1 - index; break; } } // Calculate the new cursor position start = start - count; end = end - count; } // Set the cursor to the new position inputRef.current.setSelectionRange(start, end); } else if (key === keyboardKeys_1.DELETE.key && props.mask[end] && props.mask[end] !== '#') { if (!isSelected) { let count = 1; // Check if the character at the cursor position is a mask character for (let index = end; index < props.mask.length; index++) { if (props.mask[index] === '#') { count = index - end; break; } } // Calculate the new cursor position start = start + count; end = end + count; } // Set the cursor to the new position inputRef.current.setSelectionRange(start, end); } } const cursor = { start: start, end: end, }; eventKeyPressRef.current = { key, cursor }; props.onKeyDown?.(event); }; const handlePasteInternal = event => { const clipboardData = event.clipboardData; const pastedData = clipboardData?.getData('Text'); const newRegex = typeof props.regex === 'string' ? new RegExp(props.regex) : props.regex; if (props.ignoreKeys?.some(key => pastedData.includes(key)) || props.disabledCopyAndPaste || (newRegex && !newRegex?.test(pastedData))) { event.preventDefault(); return; } pasteRef.current = true; props.onPaste?.(event); }; return { value, state, inputRef, eventKeyPressRef, handleChangeInternal, handleBlurInternal, handleFocusInternal, handleKeyDownInternal, handleSetValue, handlePasteInternal, }; }; exports.useInput = useInput; //# sourceMappingURL=useInput.js.map