react-forminate
Version:
React.js + Typescript package that creates dynamic UI forms based on the JSON schema
199 lines (198 loc) • 6.51 kB
JavaScript
import { a as M, c as K, j as n } from "./index-BPZpMa2Y.js";
import L, { useState as b, useRef as y, useMemo as D, useEffect as m } from "react";
/* empty css */
const T = (N) => {
const {
processedProps: c,
fieldParams: I,
eventHandlers: h,
fieldValue: p,
fieldId: s,
dynamicOptions: $,
fieldErrors: O,
setValue: x,
validateField: A
} = M(N), [a, i] = b(!1), [d, u] = b(""), [l, w] = b([]), [o, g] = b(-1), S = y(null), C = y(null), k = y(null), f = D(() => {
const e = $?.[s] || c.options || [];
return typeof e[0] == "string" ? e.map((t) => ({ label: t, value: t })) : e;
}, [$, s, c.options]), E = K(
(e) => u(e),
c.debounceSearch || 300
), v = D(() => d ? f.filter(
(e) => e.label.toLowerCase().includes(d.toLowerCase())
) : f, [f, d]);
m(() => {
p !== void 0 && w(Array.isArray(p) ? p : [p]);
}, [p]), m(() => {
const e = (t) => {
S.current && !S.current.contains(t.target) && (i(!1), u(""));
};
return document.addEventListener("mousedown", e), () => document.removeEventListener("mousedown", e);
}, []), m(() => {
a && C.current && (C.current.focus(), g(-1));
}, [a]), m(() => {
if (o >= 0 && k.current) {
const e = k.current.querySelectorAll(
".multiselect-option-item"
);
e[o] && e[o].scrollIntoView({
block: "nearest",
behavior: "smooth"
});
}
}, [o]), m(() => {
h.customHandlers?.onChangeItems && h.customHandlers.onChangeItems(l, s);
}, [l]), m(() => {
h.customHandlers?.onSearch && h.customHandlers.onSearch(
f,
l,
s,
d
);
}, [d]);
const R = (e) => {
if (!a) {
["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key) && (i(!0), e.preventDefault());
return;
}
switch (e.key) {
case "ArrowDown":
g(
(t) => Math.min(t + 1, v.length - 1)
), e.preventDefault();
break;
case "ArrowUp":
g((t) => Math.max(t - 1, -1)), e.preventDefault();
break;
case "Enter":
case " ":
o >= 0 && o < v.length && j(v[o].value), e.preventDefault();
break;
case "Escape":
i(!1), u(""), e.preventDefault();
break;
case "Tab":
i(!1), u("");
break;
}
}, V = () => {
i(!a), u("");
}, j = (e) => {
const t = l.includes(e) ? l.filter((r) => r !== e) : [...l, e];
w(t), x(s, t), c?.validateOnChange && A(s, t);
}, P = (e, t) => {
t.stopPropagation();
const r = l.filter((H) => H !== e);
w(r), x(s, r);
}, F = (e) => {
e.stopPropagation(), w([]), x(s, []), i(!1);
};
return /* @__PURE__ */ n.jsxs(
"div",
{
className: `multiselect-wrapper ${c.className || ""}`,
ref: S,
onKeyDown: R,
role: "combobox",
"aria-haspopup": "listbox",
"aria-expanded": a,
"aria-owns": `${s}-dropdown`,
"aria-controls": `${s}-dropdown`,
...I,
children: [
/* @__PURE__ */ n.jsxs(
"div",
{
className: `form-element multiselect-input-container ${O ? "form-element-error" : ""} ${a ? "multiselect-input-container-open" : ""}`,
onClick: V,
tabIndex: 0,
children: [
l.length === 0 ? /* @__PURE__ */ n.jsx("span", { className: "multiselect-placeholder", children: c.placeholder || "Select options" }) : l.map((e) => {
const t = f.find((r) => r.value === e);
return /* @__PURE__ */ n.jsxs("div", { className: "multiselect-selected-tag", children: [
t ? t.label : e,
/* @__PURE__ */ n.jsx(
"span",
{
className: "multiselect-remove-tag",
onClick: (r) => P(e, r),
"aria-label": `Remove ${t?.label || e}`,
children: "×"
}
)
] }, e);
}),
c.showClearAll && l.length > 0 && /* @__PURE__ */ n.jsx(
"button",
{
type: "button",
className: "multiselect-clear-all",
onClick: F,
"aria-label": "Clear all selections",
onKeyDown: (e) => e.stopPropagation(),
children: "Clear all"
}
),
/* @__PURE__ */ n.jsx(
"span",
{
className: `multiselect-chevron-icon ${a ? "multiselect-chevron-icon-open" : ""}`,
"aria-hidden": "true",
children: "▼"
}
)
]
}
),
/* @__PURE__ */ n.jsxs(
"div",
{
className: `multiselect-dropdown ${a ? "" : "multiselect-dropdown-hidden"}`,
ref: k,
role: "listbox",
id: `${s}-dropdown`,
"aria-multiselectable": "true",
children: [
/* @__PURE__ */ n.jsx("div", { className: "multiselect-search-container", children: /* @__PURE__ */ n.jsx(
"input",
{
ref: C,
type: "text",
className: "multiselect-search-input",
placeholder: "Search...",
value: d,
onChange: (e) => {
u(e.target.value), E(e.target.value);
},
onClick: (e) => e.stopPropagation(),
"aria-label": "Search options",
onKeyDown: (e) => {
e.key === "Escape" && i(!1);
}
}
) }),
v.map((e, t) => /* @__PURE__ */ n.jsxs(
"div",
{
className: `multiselect-option-item ${l.includes(e.value) ? "multiselect-option-selected" : ""} ${t === o ? "multiselect-option-focused" : ""}`,
onClick: () => j(e.value),
role: "option",
"aria-selected": l.includes(e.value),
id: `${s}-option-${t}`,
children: [
e.label,
l.includes(e.value) && " ✓"
]
},
e.value
))
]
}
)
]
}
);
}, B = L.memo(T);
export {
B as default
};