UNPKG

geoiq-frontend-ui-kit

Version:

This project is a UI kit for GeoIQ's frontend. It's built with React, TypeScript, and Vite.

278 lines (277 loc) 9.36 kB
import n, { useState as b, useRef as ue, useCallback as pe, useEffect as he, useMemo as D } from "react"; import { X as ge, ChevronUp as ye, ChevronDown as be, Plus as we, Check as Ee } from "lucide-react"; import { Command as Ce, CommandInput as Ne, CommandEmpty as xe, CommandGroup as ve, CommandList as je, CommandItem as K } from "./index.es56.js"; import { Popover as ke, PopoverTrigger as Se, PopoverContent as Le } from "./index.es86.js"; import { Button as Ae } from "./index.es9.js"; import { Typography as w } from "./index.es19.js"; import { Badge as Pe } from "./index.es8.js"; import { cn as R } from "./index.es85.js"; import { ComboBoxStates as Oe } from "./index.es104.js"; import { interpolateUrl as Q } from "./index.es105.js"; function Me(o) { const c = (a) => typeof a == "string" ? { id: a, name: a } : { id: String(a.id ?? a.value ?? a.email ?? a), name: String(a.name ?? a.label ?? a.id ?? a.value ?? a.email ?? a) }; if (Array.isArray(o)) return o.map(c); if (o && typeof o == "object") { const a = o.data ?? o.options; if (Array.isArray(a)) return a.map(c); } return []; } function _e(o, c) { if (o && typeof o == "object") { const a = o.data ?? o; if (a && typeof a == "object") { const m = a; return { id: String(m.id ?? m.value ?? m.email ?? c), name: String(m.name ?? m.label ?? m.id ?? m.value ?? m.email ?? c) }; } } return { id: c, name: c }; } async function U(o) { if (!o) return {}; const c = typeof o == "function" ? o() : o; return await Promise.resolve(c) ?? {}; } function Xe({ optionsUrl: o, createOptionUrl: c, fetchOptions: a, createOption: m, requestHeaders: P, optionsRequestBody: V, createOptionRequestBody: Y, createOptionValueKey: Z = "value", createOptionExtraBody: O, skipCreateOptionExtraBody: I, urlTemplateData: v = {}, value: f, fieldId: j, placeholder: H = "Select or type...", searchPlaceholder: q = "Search or type a value...", emptyMessage: ee = "No options", addCustomMessage: te = (p) => `Add "${p}"`, minSelected: M = 0, maxSelected: l, onChange: k, container: ne }) { const [p, _] = b(!1), [d, S] = b(""), [T, h] = b([]), [ae, L] = b(!0), [$, A] = b(!1), [B, g] = b(null), z = ue(null), G = pe(async () => { if (a) { L(!0); try { const t = await a(); h(t); } catch { h([]); } finally { L(!1); } return; } const e = o && Q(o, { ...v, fieldId: j }); if (e) { L(!0); try { const t = await U(P), s = V ?? { ...v, fieldId: j }, r = await (await fetch(e, { method: "POST", headers: { "Content-Type": "application/json", ...t }, body: JSON.stringify(s) })).json(); h(Me(r)); } catch { h([]); } finally { L(!1); } } }, [ o, v, j, a, P, V ]); he(() => { G(); }, [G]); const E = D(() => { const e = f ?? [], t = T.map((r) => ({ id: r.id, name: r.name })), s = e.filter( (r) => r?.trim() && !t.some((u) => u.id === r.trim()) ).map((r) => ({ id: r.trim(), name: r.trim() })), i = [...t]; for (const r of s) i.some((u) => u.id === r.id) || i.push(r); return i; }, [T, f]), re = D(() => { if (!d.trim()) return E; const e = d.toLowerCase(); return E.filter( (t) => t.name.toLowerCase().includes(e) || t.id.toLowerCase().includes(e) ); }, [E, d]), F = l != null && (f ?? []).length >= l, oe = !F && d.trim() && !E.some( (e) => e.id.toLowerCase() === d.trim().toLowerCase() || e.name.toLowerCase() === d.trim().toLowerCase() ), se = (e) => { const t = f ?? [], i = t.includes(e) ? t.filter((r) => r !== e) : [...t, e]; l != null && i.length > l || k(i); }, ie = async () => { const e = d.trim(); if (!e || F) return; if (g(null), m) { A(!0); try { const s = await m(e); h((r) => r.some((u) => u.id === s.id) ? r : [...r, s]); const i = [...f ?? [], s.id]; (l == null || i.length <= l) && k(i), S(""), _(!1); } catch (s) { const i = s instanceof Error ? s.message : String(s); g(i || "Failed to add option"); } finally { A(!1); } return; } const t = c && Q(c, { ...v, fieldId: j, value: e }); if (t) { A(!0); try { const s = await U(P), i = I ? {} : typeof O == "function" ? await Promise.resolve(O()) : O ?? {}, r = { ...Y, [Z]: e, ...i }, u = await fetch(t, { method: "POST", headers: { "Content-Type": "application/json", ...s }, body: JSON.stringify(r) }), N = await u.text(); if (!u.ok) { let y = N; try { const x = JSON.parse(N); y = String(x.message ?? x.error ?? x.msg ?? N); } catch { } g(y || "Failed to add option"); return; } const fe = N ? JSON.parse(N) : {}, J = _e(fe, e); h((y) => y.some((x) => x.id === J.id) ? y : [...y, J]); const X = [...f ?? [], J.id]; (l == null || X.length <= l) && k(X), S(""), _(!1); } catch { g("Failed to add option"); } finally { A(!1); } } }, le = (e) => { const t = (f ?? []).filter((s) => s !== e); k(t); }, ce = (e) => { _(e), e || (S(""), g(null)); }, C = f ?? [], W = C.map((e) => E.find((t) => t.id === e)).filter(Boolean), me = M > 0 && C.length < M, de = l != null && C.length > l; return /* @__PURE__ */ n.createElement(ke, { open: p, onOpenChange: ce }, /* @__PURE__ */ n.createElement(Se, { ref: z, asChild: !0 }, /* @__PURE__ */ n.createElement( Ae, { variant: "secondary", role: "combobox", "aria-expanded": p, className: R( Oe({ isOpen: p, isValue: C.length > 0 }), "w-full justify-between px-3 py-2 min-h-[40px] h-fit" ) }, /* @__PURE__ */ n.createElement("div", { className: "flex flex-wrap gap-1 flex-1 min-w-0" }, W.length > 0 ? W.map((e) => /* @__PURE__ */ n.createElement( Pe, { key: e.id, variant: "default", size: "sm", showBorder: !0, className: "gap-1" }, /* @__PURE__ */ n.createElement("span", { className: "truncate max-w-[120px]" }, e.name), /* @__PURE__ */ n.createElement( "button", { type: "button", className: "ml-0.5 rounded-full outline-none hover:bg-light-3", onMouseDown: (t) => t.preventDefault(), onClick: (t) => { t.stopPropagation(), le(e.id); } }, /* @__PURE__ */ n.createElement(ge, { className: "w-3 h-3" }) ) )) : /* @__PURE__ */ n.createElement(w, { variant: "body2", className: "text-light-4" }, H)), p ? /* @__PURE__ */ n.createElement(ye, { className: "w-4 h-4 ml-2 stroke-light-2 shrink-0" }) : /* @__PURE__ */ n.createElement(be, { className: "w-4 h-4 ml-2 stroke-light-2 shrink-0" }) )), /* @__PURE__ */ n.createElement( Le, { style: { width: z.current?.clientWidth }, className: "p-0 mt-1 rounded-lg bg-light-1", container: ne }, /* @__PURE__ */ n.createElement(Ce, { shouldFilter: !1 }, /* @__PURE__ */ n.createElement( Ne, { placeholder: q, value: d, onValueChange: (e) => { S(e), g(null); } } ), /* @__PURE__ */ n.createElement(xe, null, /* @__PURE__ */ n.createElement(w, { variant: "body3", className: "text-light-4" }, ae ? "Loading..." : ee)), /* @__PURE__ */ n.createElement(ve, null, /* @__PURE__ */ n.createElement(je, null, oe && /* @__PURE__ */ n.createElement( K, { value: `__add__${d.trim()}`, className: "text-brand hover:bg-light-2 focus:bg-light-2 gap-2", onSelect: ie, disabled: $ }, /* @__PURE__ */ n.createElement(we, { className: "h-4 w-4" }), $ ? "Adding..." : te(d.trim()) ), re.map((e) => { const t = C.includes(e.id), s = !t && F; return /* @__PURE__ */ n.createElement( K, { key: e.id, value: e.id, disabled: s, className: R( "justify-between gap-2 text-light-2 hover:bg-light-2 hover:text-light-1 focus:bg-light-2 focus:text-accent-foreground", t ? "bg-light-2" : "", s ? "opacity-50" : "" ), onSelect: () => se(e.id) }, /* @__PURE__ */ n.createElement(w, { variant: "body2" }, e.name), t ? /* @__PURE__ */ n.createElement(Ee, { className: R("h-4 w-4 stroke-brand") }) : /* @__PURE__ */ n.createElement("div", null) ); })))), B && /* @__PURE__ */ n.createElement(w, { variant: "body5", className: "text-danger-1 px-3 py-2" }, B) ), me && /* @__PURE__ */ n.createElement(w, { variant: "body5", className: "text-danger-1 mt-1" }, "Select at least ", M, " option(s)", l != null && ` (max ${l})`), de && /* @__PURE__ */ n.createElement(w, { variant: "body5", className: "text-danger-1 mt-1" }, "Select at most ", l, " option(s)")); } export { Xe as CreatableMultiCombobox }; //# sourceMappingURL=index.es28.js.map