alinea
Version:
Headless git-based CMS
114 lines (112 loc) • 3.11 kB
JavaScript
import "../../chunks/chunk-NZLE2WMY.js";
// src/dashboard/hook/UseFocusList.tsx
import {
createContext,
useContext,
useLayoutEffect,
useMemo,
useRef
} from "react";
import { jsx } from "react/jsx-runtime";
var context = createContext(void 0);
function useFocusList({ onClear }) {
const focusRef = useRef();
const { reSelect, ...res } = useMemo(() => {
const selects = /* @__PURE__ */ new WeakMap();
let current;
let items = [];
let itemsReset = true;
let selectTimeout;
function select(element) {
if (current) current.removeAttribute("aria-selected");
if (!element) return current = void 0;
element.setAttribute("aria-selected", "true");
current = element;
current.scrollIntoView({ block: "nearest" });
}
function navigate(direction) {
if (current) {
const index = items.indexOf(current);
const next = items[index + direction];
if (next) return select(next);
}
select(items[direction === 1 ? 0 : items.length - 1]);
}
function onKeyDown(event) {
switch (event.key) {
case "ArrowUp":
navigate(-1);
event.preventDefault();
break;
case "ArrowDown":
navigate(1);
event.preventDefault();
break;
case "Escape":
event.currentTarget.blur();
event.preventDefault();
onClear();
break;
case "Enter":
event.preventDefault();
selects.get(current ?? items[0])?.();
break;
default:
}
}
const focusProps = {
ref: focusRef,
onKeyDown,
/*onFocus() {
selectFirst()
},*/
onBlur() {
select(void 0);
itemsReset = true;
}
};
function registerItem(onSelect, element) {
let i = 0;
for (const item of items) {
const position = element.compareDocumentPosition(item);
if (position & Node.DOCUMENT_POSITION_FOLLOWING) break;
i++;
}
items.splice(i, 0, element);
selects.set(element, onSelect);
return () => {
if (current === element) current = void 0;
items = items.filter((item) => item !== element);
};
}
function Container({ children }) {
return /* @__PURE__ */ jsx(context.Provider, { value: { registerItem }, children });
}
function selectFirst() {
if (document.activeElement !== focusRef.current && !focusRef.current?.contains(document.activeElement))
return;
if (!itemsReset) return;
if (!current) select(items[0]);
itemsReset = false;
}
function reSelect2() {
itemsReset = true;
}
return { focusProps, Container, reSelect: reSelect2 };
}, []);
useLayoutEffect(reSelect);
return res;
}
function useFocusListItem(onSelect) {
const ctx = useContext(context);
const itemRef = useRef(null);
useLayoutEffect(() => {
if (itemRef.current && ctx)
return ctx.registerItem(onSelect, itemRef.current);
}, []);
return itemRef;
}
export {
useFocusList,
useFocusListItem
};