phx-react
Version:
PHX REACT
192 lines • 15.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PHXInput = void 0;
const tslib_1 = require("tslib");
const react_1 = tslib_1.__importStar(require("react"));
const types_1 = require("../types");
const Button_1 = require("../Button");
const ErrorMessage_1 = tslib_1.__importDefault(require("../../commons/ErrorMessage"));
const OutlineIcons = tslib_1.__importStar(require("@heroicons/react/24/outline"));
const Loading_1 = require("../Loading");
function AddNewButton({ className = '', onAddNew, searchValue, setShowList, }) {
return (react_1.default.createElement("button", { "aria-expanded": 'false', "aria-haspopup": 'listbox', className: `inset-y-0 right-0 flex w-full items-center rounded-md px-2 py-3 pr-4 font-sans text-xs text-gray-600 transition-colors hover:bg-[#e3e3e3] focus:outline-none ${className}`, onClick: () => {
if (onAddNew) {
onAddNew(searchValue);
}
setShowList(false);
}, tabIndex: -1, type: 'button' },
react_1.default.createElement("p", { className: 'flex w-full items-center text-left' },
react_1.default.createElement("span", { className: 'flex items-center font-bold' },
react_1.default.createElement("svg", { className: 'mr-1', fill: 'none', height: '20', viewBox: '0 0 20 20', width: '20', xmlns: 'http://www.w3.org/2000/svg' },
react_1.default.createElement("path", { d: 'M5.83334 9.99995C5.83334 9.53971 6.20644 9.16661 6.66667 9.16661H9.16667V6.66661C9.16667 6.20637 9.53977 5.83328 10 5.83328C10.4602 5.83328 10.8333 6.20637 10.8333 6.66661V9.16661H13.3333C13.7936 9.16661 14.1667 9.53971 14.1667 9.99995C14.1667 10.4602 13.7936 10.8333 13.3333 10.8333H10.8333V13.3333C10.8333 13.7935 10.4602 14.1666 10 14.1666C9.53977 14.1666 9.16667 13.7935 9.16667 13.3333V10.8333H6.66667C6.20644 10.8333 5.83334 10.4602 5.83334 9.99995Z', fill: '#908E8E' }),
react_1.default.createElement("path", { clipRule: 'evenodd', d: 'M10 17.7777C14.2956 17.7777 17.7778 14.2955 17.7778 9.99995C17.7778 5.7044 14.2956 2.22217 10 2.22217C5.70446 2.22217 2.22223 5.7044 2.22223 9.99995C2.22223 14.2955 5.70446 17.7777 10 17.7777ZM10 16.1111C13.3751 16.1111 16.1111 13.375 16.1111 9.99995C16.1111 6.62487 13.3751 3.88883 10 3.88883C6.62493 3.88883 3.8889 6.62487 3.8889 9.99995C3.8889 13.375 6.62493 16.1111 10 16.1111Z', fill: '#908E8E', fillRule: 'evenodd' })),
"Th\u00EAm:"),
react_1.default.createElement("span", { className: 'ml-1 truncate' }, searchValue))));
}
const ButtonAction = ({ buttonAction, showPopup, setShowPopup, }) => {
return (react_1.default.createElement("div", { className: 'relative' },
react_1.default.createElement(Button_1.PHXButton, { className: 'h-full w-full outline-none transition-all focus:outline-none focus:ring-0', onClick: () => {
var _a;
if (buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.popupContent) {
setShowPopup(!showPopup);
}
else {
(_a = buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.onClick) === null || _a === void 0 ? void 0 : _a.call(buttonAction);
}
}, secondary: true, size: 'micro' }, buttonAction.content),
(buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.popupContent) && showPopup && (react_1.default.createElement("div", { className: 'absolute left-0 top-full z-50 mt-1' }, buttonAction.popupContent(() => setShowPopup(false))))));
};
const PHXInput = ({ className, error, errorType, errorMessageCustom, helpText, label, register, registerSelect, listOption, disabled, selected, prefix, suffix, prefixIcon, suffixIcon, labelAction, buttonAction, searchConfig, onChange, isSearchInput = false, ...rest }) => {
const message = (type) => {
let errorMessage = '';
switch (type) {
case 'required-field':
errorMessage = 'Vui lòng nhập thông tin';
break;
case 'validate-input-field':
errorMessage = 'Vui lòng nhập thông tin hợp lệ (độ dài 1 - 60 kí tự)';
break;
case 'duplicate-field':
errorMessage = 'Thông tin đã tồn tại';
break;
case 'validate-phone-number':
errorMessage = 'Số điện thoại chưa hợp lệ';
break;
case 'validate-input-email':
errorMessage = 'Định dạng email chưa đúng, vui lòng nhập lại';
break;
case 'custom-message':
errorMessage = errorMessageCustom;
break;
default:
break;
}
return errorMessage;
};
const PrefixIconComponent = prefixIcon ? OutlineIcons[prefixIcon] : null;
const SuffixIconComponent = suffixIcon ? OutlineIcons[suffixIcon] : null;
const isSearchMode = isSearchInput && !!searchConfig;
const wrapperRef = (0, react_1.useRef)(null);
const [showList, setShowList] = (0, react_1.useState)(false);
const [searchValue, setSearchValue] = (0, react_1.useState)(isSearchMode ? (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.defaultText) || '' : '');
const [listData, setListData] = (0, react_1.useState)([]);
const [loading, setLoading] = (0, react_1.useState)(false);
const [showAddnew, setShowAddNew] = (0, react_1.useState)(false);
const [showPopup, setShowPopup] = (0, react_1.useState)(false);
const handleSearch = async () => {
if (!isSearchMode || !searchConfig || !searchValue) {
setListData([]);
return;
}
try {
setLoading(true);
const results = await searchConfig.onSearch(searchValue);
setListData(results || []);
setShowAddNew(true);
}
catch (e) {
console.error('Search Error:', e);
setListData([]);
}
finally {
setLoading(false);
}
};
(0, react_1.useEffect)(() => {
if (!isSearchMode)
return;
if (!loading) {
setLoading(true);
}
const timerId = setTimeout(() => {
handleSearch();
}, 300);
return () => clearTimeout(timerId);
}, [searchValue]);
(0, react_1.useEffect)(() => {
const handleClickOutside = (event) => {
var _a;
if (wrapperRef.current && !((_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target))) {
setShowList(false);
setShowPopup(false);
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [wrapperRef]);
const handleSelectItem = (item) => {
if (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.onClickSearchItem) {
const value = searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.onClickSearchItem(item);
setSearchValue(value);
}
else {
setSearchValue('');
}
setShowList(false);
};
const handleInputChange = (event) => {
const value = event.target.value;
if (!isSearchMode) {
if (onChange)
onChange(event);
return;
}
if (!showList)
setShowList(true);
if (!value && (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.onClear)) {
searchConfig.onClear();
}
setSearchValue(value);
};
const isExistName = listData === null || listData === void 0 ? void 0 : listData.some((item) => { var _a; return ((_a = item === null || item === void 0 ? void 0 : item.name) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === (searchValue === null || searchValue === void 0 ? void 0 : searchValue.toLowerCase()); });
const inputProps = isSearchMode
? {
value: searchValue,
onChange: handleInputChange,
}
: {
onChange: (e) => {
if (onChange)
onChange(e);
},
};
const isLeftButtonAction = buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.isLeftPosition;
return (react_1.default.createElement("div", { className: className, ref: wrapperRef },
react_1.default.createElement("div", { className: (0, types_1.classNames)(label ? 'flex mb-1 text-xs font-normal text-gray-700' : 'hidden', label && (labelAction === null || labelAction === void 0 ? void 0 : labelAction.content) ? 'justify-between' : '') },
label && react_1.default.createElement("label", null, label),
(labelAction === null || labelAction === void 0 ? void 0 : labelAction.content) && (react_1.default.createElement("p", { className: 'text-blue-600 hover:cursor-pointer hover:text-blue-800 hover:underline', onClick: labelAction.onClick }, labelAction.content))),
react_1.default.createElement("div", { className: (0, types_1.classNames)((buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.content) ? 'flex gap-x-2' : '') },
(buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.content) && isLeftButtonAction && (react_1.default.createElement(ButtonAction, { buttonAction: buttonAction, showPopup: showPopup, setShowPopup: setShowPopup })),
react_1.default.createElement("div", { className: (0, types_1.classNames)((buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.content) ? 'relative flex-1' : 'relative') },
react_1.default.createElement("input", { ...register, ...rest, ...inputProps, disabled: disabled, onChange: (e) => {
var _a;
if (isSearchMode) {
handleInputChange(e);
return;
}
(_a = register === null || register === void 0 ? void 0 : register.onChange) === null || _a === void 0 ? void 0 : _a.call(register, e);
onChange === null || onChange === void 0 ? void 0 : onChange(e);
}, className: (0, types_1.classNames)('block w-full border-[0.5px] rounded-lg border-gray-500 py-1.5 px-3 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', error ? 'border-red-800 bg-red-50 hover:bg-red-50 focus:border-red-800 focus:bg-red-50' : '', disabled ? 'bg-neutral-200 border-[0px] hover:bg-neutral-200' : '', (!prefix || !prefixIcon) && 'pl-3', (!suffix || !suffixIcon) && 'pr-3'), style: {
paddingLeft: `${prefix ? prefix.length + 2 + 'ch' : prefixIcon ? 28 + 'px' : 12 + 'px'}`,
paddingRight: `${suffix ? suffix.length + 2 + 'ch' : suffixIcon ? 28 + 'px' : 12 + 'px'}`,
} }),
prefix && react_1.default.createElement("div", { className: 'absolute top-[0.425rem] left-2.5 text-gray-500 text-xs' }, prefix),
suffix && react_1.default.createElement("div", { className: 'absolute top-[0.425rem] right-2.5 text-gray-500 text-xs' }, suffix),
PrefixIconComponent && (react_1.default.createElement("div", { className: 'absolute inset-y-0 left-2.5 flex items-center text-gray-500' },
react_1.default.createElement(PrefixIconComponent, { className: 'h-4 w-4' }))),
SuffixIconComponent && (react_1.default.createElement("div", { className: 'absolute inset-y-0 right-2.5 flex items-center text-gray-500' },
react_1.default.createElement(SuffixIconComponent, { className: 'h-4 w-4' }))),
listOption && (react_1.default.createElement("div", { className: 'absolute inset-y-0 right-0 flex items-center' },
react_1.default.createElement("select", { id: 'unit', ...registerSelect, className: 'h-full rounded-md border-0 bg-transparent py-0 pl-2 pr-7 text-gray-600 focus:ring-2 focus:ring-inset focus:ring-indigo-600 text-xs font-normal' }, listOption.map((item) => (react_1.default.createElement("option", { key: item.id, value: item.id, selected: selected === item.id }, item.name)))))),
isSearchMode && showList && searchValue && (react_1.default.createElement("div", { className: 'absolute z-50 mt-1 w-full overflow-hidden rounded-xl bg-white drop-shadow-xl' }, !loading ? (listData.length > 0 ? (react_1.default.createElement("div", { className: 'r mt-[2px] max-h-[250px] min-w-full divide-gray-200 overflow-y-auto rounded-xl border-[0.5px] px-2 py-1 ' },
!isExistName && (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.onAddNew) && (react_1.default.createElement(AddNewButton, { className: '!mt-1 !py-[6px] !pl-1', onAddNew: (value) => { var _a; return (_a = searchConfig.onAddNew) === null || _a === void 0 ? void 0 : _a.call(searchConfig, value); }, searchValue: searchValue, setShowList: setShowList })),
listData.map((item) => (react_1.default.createElement("button", { key: Math.random(), "aria-expanded": 'false', "aria-haspopup": 'listbox', "aria-labelledby": 'headlessui-combobox-label-:rk: headlessui-combobox-button-:rm:', className: 'inset-y-0 right-0 my-1 mt-1 flex w-full items-center rounded-md px-2 py-[6px] pr-4 font-sans text-xs text-gray-600 transition-colors hover:bg-[#e3e3e3] focus:outline-none', "data-headlessui-state": '', disabled: item.is_selected, onClick: () => handleSelectItem(item), tabIndex: -1, type: 'button' }, (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.renderItem) && searchConfig.renderItem(item)))))) : (react_1.default.createElement("div", { className: 'bg-whitetext-center mt-1 rounded-[10px] border-[1px] shadow-gray-900' }, (searchConfig === null || searchConfig === void 0 ? void 0 : searchConfig.onAddNew) && showAddnew && (react_1.default.createElement(AddNewButton, { onAddNew: (value) => { var _a; return (_a = searchConfig.onAddNew) === null || _a === void 0 ? void 0 : _a.call(searchConfig, value); }, searchValue: searchValue, setShowList: setShowList }))))) : (react_1.default.createElement("div", { className: 'mt-2 h-[50px] rounded-[10px] border-[1px] bg-white py-3 text-center shadow-gray-900' },
react_1.default.createElement(Loading_1.PHXSpinner, null)))))),
(buttonAction === null || buttonAction === void 0 ? void 0 : buttonAction.content) && !isLeftButtonAction && (react_1.default.createElement(ButtonAction, { buttonAction: buttonAction, showPopup: showPopup, setShowPopup: setShowPopup }))),
helpText ? react_1.default.createElement("div", { className: 'mt-1 text-xs text-gray-500' }, helpText) : null,
error && errorType ? react_1.default.createElement(ErrorMessage_1.default, { message: message(errorType) }) : null));
};
exports.PHXInput = PHXInput;
//# sourceMappingURL=Input.js.map