UNPKG

phx-react

Version:

PHX REACT

140 lines 7.2 kB
import { ClockIcon } from '@heroicons/react/24/outline'; import React, { useEffect, useRef, useState } from 'react'; import Time from './component/Time'; import ErrorMessage from '../../commons/ErrorMessage'; import { toMinutes } from './utils'; function classNames(...classes) { return classes.filter(Boolean).join(' '); } export function PHXTimePicker({ className, defaultValue, disabled, readOnly, error, errorType, errorMessageCustom, id = 'time-picker', origin = 'bottom-left', label, onChange, register, step, min, max, helpText, placeholder, setValueUseForm, keySetValueUseForm, hideDisable = false, }) { const message = (type) => { let errorMessage = ''; switch (type) { case 'required-field': errorMessage = 'Vui lòng nhập thông tin'; break; case 'custom-message': errorMessage = errorMessageCustom; break; default: break; } return errorMessage; }; const inputRef = useRef(null); const calendarRef = useRef(null); const [isCalendarVisible, setIsCalendarVisible] = useState(false); const [inputValue, setInputValue] = useState(''); const [isOnChange, setIsOnChange] = useState(false); const handleToggleCalendar = () => { setIsCalendarVisible((prev) => !prev); }; useEffect(() => { if (defaultValue) { // @ts-ignore setInputValue(defaultValue); } else { return; } }, [defaultValue]); useEffect(() => { const modalElement = document.getElementById('modal'); const handleClickOutside = (event) => { setTimeout(() => { if (calendarRef.current && !calendarRef.current.contains(event.target) && inputRef.current && !inputRef.current.contains(event.target)) { setIsCalendarVisible(false); const inputElement = document.getElementById(`${id}-after`); if (inputElement && isOnChange) { inputElement.focus(); setIsOnChange(false); inputElement.blur(); } } }, 200); }; document.addEventListener('mousedown', handleClickOutside); if (modalElement) { modalElement.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, []); const handleChange = (val) => { const inputElement = document.getElementById(`${id}-after`); if (inputElement) inputElement.focus(); setInputValue(val); if (setValueUseForm && keySetValueUseForm) { setValueUseForm(keySetValueUseForm, val); } if (onChange) { onChange(val); } }; const handleChangeInput = (event) => { setIsOnChange(true); let value = event.target.value; // Chỉ cho phép nhập các ký tự số và : value = value.replace(/[^0-9:]/g, ''); // Kiểm tra xem giá trị có độ dài phù hợp để thêm dấu : tự động if (value.length === 2 && !value.includes(':')) { value = value + ':'; } // Xóa dấu : nếu người dùng xóa nó if (value.length === 2 && event.nativeEvent.inputType === 'deleteContentBackward') { value = value.substring(0, value.length - 1); } // Cập nhật giá trị thời gian setInputValue(value); if (value.length === 5 && /^\d{2}:\d{2}$/.test(value)) { const [hour, minute] = value.split(':').map(Number); if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { setInputValue(min || '00:00'); } const inputMinutes = hour * 60 + minute; const minMinutes = min ? toMinutes(min) : undefined; const maxMinutes = max ? toMinutes(max) : undefined; if ((minMinutes && inputMinutes < minMinutes) || (maxMinutes && inputMinutes > maxMinutes)) { setInputValue(min || '00:00'); } } if (onChange) { onChange(value); } }; const value = () => { switch (true) { case !!defaultValue && !!inputValue: return inputValue; case !!defaultValue && !inputValue: return defaultValue; default: return inputValue; } }; return (React.createElement(React.Fragment, null, React.createElement("div", { className: className }, label && React.createElement("label", { className: 'block mb-1 text-xs font-normal text-gray-700' }, label), React.createElement("div", { className: 'relative' }, React.createElement("label", { ref: inputRef, className: 'absolute top-0 h-[1.875rem] w-full rounded-lg py-4', htmlFor: id, onClick: handleToggleCalendar }), React.createElement("input", { className: classNames('block w-full rounded-lg border-[0.5px] border-gray-500 px-3 py-1.5 pl-9 text-xs font-normal shadow-sm hover:bg-gray-50 focus:border-gray-500 focus:bg-gray-50 focus:outline-none focus:outline-offset-1 focus:outline-indigo-500 focus:ring-transparent', disabled ? '!border-gray-100 bg-gray-100 text-gray-400 hover:!bg-gray-100' : '', error ? 'border-red-800 bg-red-50 hover:bg-red-50 focus:border-red-800 focus:bg-red-50' : ''), disabled: disabled, id: id, onChange: (event) => handleChangeInput(event), value: value(), placeholder: placeholder, readOnly: readOnly }), React.createElement("input", { className: 'hidden rounded-lg', id: `${id}-after`, style: { content: '', position: 'absolute', height: 0, top: 0, zIndex: -100, }, ...register, value: value(), readOnly: readOnly }), error && errorType ? React.createElement(ErrorMessage, { message: message(errorType) }) : null, React.createElement("div", { className: 'absolute left-3 top-2' }, React.createElement(ClockIcon, { className: 'w-4 h-4 text-gray-500' })), React.createElement("div", { ref: calendarRef, className: classNames('absolute z-50 w-full max-w-[20rem]', origin === 'top-left' && '-top-[17.5rem] left-0', origin === 'top-right' && '-top-[17.5rem] right-0', origin === 'bottom-left' && 'left-0 top-10', origin === 'bottom-right' && 'right-0 top-10', isCalendarVisible && !disabled ? '' : 'hidden') }, React.createElement(Time, { setIsCalendarVisible: setIsCalendarVisible, onChangeTime: (val) => handleChange(val), step: step, min: min, max: max, hideDisable: hideDisable }))), helpText ? React.createElement("div", { className: 'mt-1 text-xs text-gray-500' }, helpText) : null))); } //# sourceMappingURL=TimePicker.js.map