@konstructio/ui
Version:
A set of reusable and customizable React components built for konstruct.io
104 lines (103 loc) • 2.57 kB
JavaScript
import { useRef as m, useEffect as c, useCallback as b } from "react";
import { useDropdownContext as L } from "../contexts/dropdown.hook.js";
const p = ({
ulRef: f,
inputRef: t,
disabled: w,
internalValue: u,
onBlur: g
}) => {
const r = m(null), a = m(null), { value: i, setSearchTerm: v, setCanFilter: d, toggleOpen: n } = L();
c(() => {
const e = new AbortController(), o = (l) => {
l.key === "Escape" && n(!1);
}, s = (l) => {
r.current?.contains(l.target) || n(!1);
};
return document.addEventListener("keydown", o, {
signal: e.signal
}), document.addEventListener("mousedown", s, {
signal: e.signal
}), document.addEventListener(
"visibilitychange",
() => {
document.hidden && n(!1);
},
{
signal: e.signal
}
), a.current?.addEventListener(
"focusin",
(l) => {
!w && l.target?.matches(":focus-visible") && n(!0);
},
{ signal: e.signal }
), () => {
e.abort();
};
}, [n, r]), c(() => {
const e = new AbortController();
return a.current?.addEventListener(
"keydown",
(o) => {
if (o.key === "ArrowDown") {
const s = f.current?.querySelector("li");
s && s.focus();
}
},
{ signal: e.signal }
), () => {
e.abort();
};
}, [a, f]), c(() => {
const e = new AbortController();
return t?.current?.addEventListener(
"focusin",
() => {
v(u?.value ?? ""), d(!1);
},
{ signal: e.signal }
), t?.current?.addEventListener(
"focusout",
() => {
d(!0);
},
{ signal: e.signal }
), a.current?.addEventListener(
"focus",
() => {
d(!1);
},
{ signal: e.signal }
), r.current?.addEventListener(
"focusout",
(o) => {
r.current?.contains(o.relatedTarget) || n(!1);
},
{ signal: e.signal }
), () => {
e.abort();
};
}, [i]), c(() => {
t?.current && (t.current.value = i && u?.value || "");
}, [u, i]), c(() => {
const e = new AbortController();
return r.current?.addEventListener("focusout", (o) => {
const s = o.relatedTarget;
(!s || !r.current?.contains(s)) && (t?.current?.value || g?.());
}), () => {
e.abort();
};
}, [n, r, v, g, i]);
const E = b(() => {
n(!0), requestAnimationFrame(() => t?.current?.focus());
}, [t, n]);
return {
wrapperRef: r,
wrapperInputRef: a,
handleOpen: E
};
};
export {
p as useDropdown
};