UNPKG

@arudovwen/react-form-builder

Version:
139 lines (131 loc) 6.64 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _clsx = _interopRequireDefault(require("clsx")); var _react = _interopRequireWildcard(require("react")); var _axios = _interopRequireDefault(require("axios")); var _react2 = require("@headlessui/react"); var _lucideReact = require("lucide-react"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } const CustomSelect = /*#__PURE__*/(0, _react.forwardRef)(({ options = [], defaultValue, onGetValue, readOnly = false, url = '' }, ref) => { const [query, setQuery] = (0, _react.useState)(''); const [debouncedQuery, setDebouncedQuery] = (0, _react.useState)(''); const [selectedValue, setSelectedValue] = (0, _react.useState)(defaultValue || null); const [fetchedOptions, setFetchedOptions] = (0, _react.useState)([]); const [loading, setLoading] = (0, _react.useState)(false); const [error, setError] = (0, _react.useState)(null); // Debounce input (0, _react.useEffect)(() => { const timeoutId = setTimeout(() => { setDebouncedQuery(query); }, 300); return () => clearTimeout(timeoutId); }, [query]); // Merge options and fetchedOptions const mergedOptions = (0, _react.useMemo)(() => [...new Map([...options, ...fetchedOptions].map(item => [`${item.value}-${item.text}`, item])).values()], [options, fetchedOptions]); // Filter options by query const filteredOptions = (0, _react.useMemo)(() => { if (debouncedQuery === '') return mergedOptions; return mergedOptions.filter(option => option.text?.toLowerCase().includes(debouncedQuery.toLowerCase())); }, [debouncedQuery, mergedOptions]); // Check if user input should be creatable const isCreatable = (0, _react.useMemo)(() => query.length > 0 && !mergedOptions.some(option => option.text.toLowerCase() === query.toLowerCase()), [query, mergedOptions, defaultValue]); // Fetch from API const fetchData = (0, _react.useCallback)(async () => { if (!url) return; setLoading(true); setError(null); try { const response = await _axios.default.get(url, { headers: { Authorization: `Bearer ${window.localStorage.getItem('token')}` }, params: { q: debouncedQuery } }); const data = Array.isArray(response.data) ? response.data : response.data?.data || []; setFetchedOptions(data); } catch (err) { console.error('Failed to load options:', err); setError('Something went wrong while fetching data.'); setFetchedOptions([]); } finally { setLoading(false); } }, [url, debouncedQuery]); (0, _react.useEffect)(() => { if (url) fetchData(); }, []); // Notify parent (0, _react.useEffect)(() => { if (onGetValue) { onGetValue(selectedValue); } }, [selectedValue]); // Helpers const getSelectedOption = value => mergedOptions.find(option => option.value === value) || { value, text: value }; const handleChange = value => { if (!mergedOptions.some(option => option.value === value)) { const newOption = { value, text: value }; setSelectedValue(value); setFetchedOptions(prev => [...prev, newOption]); } else { setSelectedValue(value); } }; return /*#__PURE__*/_react.default.createElement("div", { className: "relative w-full", ref: ref }, /*#__PURE__*/_react.default.createElement(_react2.Combobox, { value: selectedValue, onChange: handleChange, disabled: readOnly }, /*#__PURE__*/_react.default.createElement("div", { className: "relative" }, /*#__PURE__*/_react.default.createElement(_react2.ComboboxInput, { disabled: readOnly, className: (0, _clsx.default)('w-full rounded-lg border border-gray-300 bg-white py-2 pr-10 pl-3 text-sm text-gray-900 disabled:bg-gray-200', 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500'), displayValue: val => getSelectedOption(val)?.text || '', onChange: event => setQuery(event.target.value), placeholder: "Select an option..." }), /*#__PURE__*/_react.default.createElement(_react2.ComboboxButton, { className: "absolute inset-y-0 right-0 flex items-center px-2 text-gray-400 hover:text-gray-600 disabled:bg-gray-200" }, /*#__PURE__*/_react.default.createElement(_lucideReact.ChevronDown, null))), /*#__PURE__*/_react.default.createElement(_react2.ComboboxOptions, { className: (0, _clsx.default)('absolute z-10 mt-2 max-h-60 w-full overflow-auto rounded-md border border-gray-200 bg-white p-1 shadow-lg', 'ring-1 ring-black ring-opacity-5 focus:outline-none') }, loading && /*#__PURE__*/_react.default.createElement("div", { className: "px-3 py-2 text-sm text-gray-500" }, "Loading..."), !loading && error && /*#__PURE__*/_react.default.createElement("div", { className: "px-3 py-2 text-sm text-red-500" }, error), !loading && !error && filteredOptions.length === 0 && !isCreatable && /*#__PURE__*/_react.default.createElement("div", { className: "px-3 py-2 text-sm text-gray-500" }, "No results found."), !loading && !error && filteredOptions.filter(i => i.value).map((option, index) => /*#__PURE__*/_react.default.createElement(_react2.ComboboxOption, { key: `${option.value}-${index}`, value: option.value, className: ({ active, selected }) => (0, _clsx.default)('cursor-default select-none rounded-md px-3 py-2 text-sm', active ? 'bg-blue-100 text-blue-900' : 'text-gray-900', selected && 'font-semibold') }, option.text)), isCreatable && /*#__PURE__*/_react.default.createElement(_react2.ComboboxOption, { value: query, className: ({ active }) => (0, _clsx.default)('cursor-pointer select-none rounded-md px-3 py-2 text-sm italic', active ? 'bg-gray-100 text-gray-900' : 'text-gray-700') }, "Add \"", /*#__PURE__*/_react.default.createElement("strong", null, query), "\"")))); }); var _default = exports.default = CustomSelect;