@veracity/vui
Version:
Veracity UI is a React component library crafted for use within Veracity applications and pages. Based on Styled Components and @xstyled.
89 lines (87 loc) • 3.01 kB
JavaScript
import { isArray, isReactText } from "../utils/assertion.js";
import { filterUndefined } from "../utils/object.js";
import { cs } from "../utils/styles.js";
import { useStyleConfig } from "../core/theme.js";
import styled from "../core/styled.js";
import vui from "../core/vui.js";
import { ListProvider } from "./context.js";
import { ListDivider } from "./listDivider.js";
import { ListHeading } from "./listHeading.js";
import { ListIcon } from "./listIcon.js";
import { ListText } from "./listText.js";
import { ListItem } from "./listItem.js";
import { useEffect, useMemo, useRef, useState } from "react";
import { jsx, jsxs } from "react/jsx-runtime";
//#region src/list/list.tsx
const clickKeys = ["Enter", " "];
const nextKeys = ["ArrowDown", "Tab"];
const prevKeys = ["ArrowUp"];
const ListBase = styled.ulBox``;
/** Displays a list of list link items and optional heading. Exposes some props to the children via context. */
const List = vui((props, ref) => {
const { children, className, heading, isInteractive, items, size, variant, ...rest } = props;
const styles = useStyleConfig("List", props);
const context = useMemo(() => filterUndefined({
isInteractive,
size,
variant
}), [
isInteractive,
size,
variant
]);
const listRef = useRef(null);
const [, setActive] = useState(-1);
const onKeydown = (event) => {
if ([
...prevKeys,
...nextKeys,
...clickKeys
].includes(event.key)) {
event.preventDefault();
setActive((a) => {
let active = a;
if (listRef.current) {
const tabIndexedChildren = Array.from(listRef.current.childNodes).filter((child) => child.tabIndex === 0);
if (nextKeys.includes(event.key) && active < tabIndexedChildren.length - 1) active++;
if (prevKeys.includes(event.key)) active = active > 0 ? active - 1 : 0;
tabIndexedChildren.forEach((node, index) => {
if (index === active) {
if (clickKeys.includes(event.key)) node?.click();
else node?.focus();
}
});
}
return active;
});
}
};
useEffect(() => {
if (listRef.current && isInteractive) {
listRef.current.addEventListener("keydown", onKeydown);
return () => {
listRef.current?.removeEventListener("keydown", onKeydown);
};
}
}, [listRef.current, isInteractive]);
return /* @__PURE__ */ jsx(ListProvider, {
value: context,
children: /* @__PURE__ */ jsxs(ListBase, {
className: cs("vui-list", className),
ref: ref || listRef,
...styles.container,
...rest,
children: [isReactText(heading) ? /* @__PURE__ */ jsx(ListHeading, { text: heading }) : heading, children ?? (isArray(items) ? items.map(({ key, ...props }, index) => /* @__PURE__ */ jsx(ListItem, { ...props }, key ?? index)) : items)]
})
});
});
List.Divider = ListDivider;
List.Heading = ListHeading;
List.Icon = ListIcon;
List.Item = ListItem;
List.Text = ListText;
List.displayName = "List";
//#endregion
export { List, List as default, ListBase };
globalThis.__vuiVersion__ = "5.3.1"
//# sourceMappingURL=list.js.map