UNPKG

@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
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