@primer/react
Version:
An implementation of GitHub's Primer Design System using React
707 lines (683 loc) • 17.2 kB
JavaScript
import { c } from 'react-compiler-runtime';
import { PlusIcon, ChevronDownIcon } from '@primer/octicons-react';
import React, { createElement, isValidElement } from 'react';
import { clsx } from 'clsx';
import { ActionList } from '../ActionList/index.js';
import { SubItem } from '../ActionList/Item.js';
import { ActionListContainerContext } from '../ActionList/ActionListContainerContext.js';
import { useId } from '../hooks/useId.js';
import useIsomorphicLayoutEffect from '../utils/useIsomorphicLayoutEffect.js';
import classes from '../ActionList/ActionList.module.css.js';
import navListClasses from './NavList.module.css.js';
import { flushSync } from 'react-dom';
import { isSlot } from '../utils/is-slot.js';
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
const Root = /*#__PURE__*/React.forwardRef((t0, ref) => {
const $ = c(10);
let children;
let props;
if ($[0] !== t0) {
({
children,
...props
} = t0);
$[0] = t0;
$[1] = children;
$[2] = props;
} else {
children = $[1];
props = $[2];
}
let t1;
if ($[3] === Symbol.for("react.memo_cache_sentinel")) {
t1 = {
container: "NavList"
};
$[3] = t1;
} else {
t1 = $[3];
}
let t2;
if ($[4] !== children) {
t2 = /*#__PURE__*/jsx(ActionListContainerContext.Provider, {
value: t1,
children: /*#__PURE__*/jsx(ActionList, {
children: children
})
});
$[4] = children;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== props || $[7] !== ref || $[8] !== t2) {
t3 = /*#__PURE__*/jsx("nav", {
...props,
ref: ref,
children: t2
});
$[6] = props;
$[7] = ref;
$[8] = t2;
$[9] = t3;
} else {
t3 = $[9];
}
return t3;
});
Root.displayName = 'NavList';
// ----------------------------------------------------------------------------
// NavList.Item
const Item = /*#__PURE__*/React.forwardRef((t0, ref) => {
const $ = c(29);
let ariaCurrent;
let children;
let defaultOpen;
let props;
if ($[0] !== t0) {
({
"aria-current": ariaCurrent,
children,
defaultOpen,
...props
} = t0);
$[0] = t0;
$[1] = ariaCurrent;
$[2] = children;
$[3] = defaultOpen;
$[4] = props;
} else {
ariaCurrent = $[1];
children = $[2];
defaultOpen = $[3];
props = $[4];
}
const {
depth
} = React.useContext(SubNavContext);
let childrenWithoutSubNavOrTrailingAction;
let subNav;
let t1;
if ($[5] !== children || $[6] !== defaultOpen) {
subNav = React.Children.toArray(children).find(_temp);
let t2;
if ($[10] !== children) {
t2 = React.Children.toArray(children).filter(_temp2);
$[10] = children;
$[11] = t2;
} else {
t2 = $[11];
}
childrenWithoutSubNavOrTrailingAction = t2;
if (! /*#__PURE__*/isValidElement(subNav) && defaultOpen) {
console.error("NavList.Item must have a NavList.SubNav to use defaultOpen.");
}
t1 = subNav && /*#__PURE__*/isValidElement(subNav);
$[5] = children;
$[6] = defaultOpen;
$[7] = childrenWithoutSubNavOrTrailingAction;
$[8] = subNav;
$[9] = t1;
} else {
childrenWithoutSubNavOrTrailingAction = $[7];
subNav = $[8];
t1 = $[9];
}
if (t1) {
let t2;
if ($[12] !== depth) {
t2 = {
"--subitem-depth": depth
};
$[12] = depth;
$[13] = t2;
} else {
t2 = $[13];
}
const t3 = t2;
let t4;
if ($[14] !== childrenWithoutSubNavOrTrailingAction || $[15] !== defaultOpen || $[16] !== depth || $[17] !== subNav || $[18] !== t3) {
t4 = /*#__PURE__*/jsx(ItemWithSubNav, {
subNav: subNav,
depth: depth,
defaultOpen: defaultOpen,
style: t3,
children: childrenWithoutSubNavOrTrailingAction
});
$[14] = childrenWithoutSubNavOrTrailingAction;
$[15] = defaultOpen;
$[16] = depth;
$[17] = subNav;
$[18] = t3;
$[19] = t4;
} else {
t4 = $[19];
}
return t4;
}
const t2 = Boolean(ariaCurrent) && ariaCurrent !== "false";
let t3;
if ($[20] !== depth) {
t3 = {
"--subitem-depth": depth
};
$[20] = depth;
$[21] = t3;
} else {
t3 = $[21];
}
const t4 = t3;
let t5;
if ($[22] !== ariaCurrent || $[23] !== children || $[24] !== props || $[25] !== ref || $[26] !== t2 || $[27] !== t4) {
t5 = /*#__PURE__*/jsx(ActionList.LinkItem, {
ref: ref,
"aria-current": ariaCurrent,
active: t2,
style: t4,
...props,
children: children
});
$[22] = ariaCurrent;
$[23] = children;
$[24] = props;
$[25] = ref;
$[26] = t2;
$[27] = t4;
$[28] = t5;
} else {
t5 = $[28];
}
return t5;
});
Item.displayName = 'NavList.Item';
// ----------------------------------------------------------------------------
// ItemWithSubNav (internal)
const ItemWithSubNavContext = /*#__PURE__*/React.createContext({
buttonId: '',
subNavId: '',
isOpen: false
});
function ItemWithSubNav(t0) {
var _ref;
const $ = c(26);
const {
children,
subNav,
defaultOpen,
style
} = t0;
const buttonId = useId();
const subNavId = useId();
const [isOpen, setIsOpen] = React.useState((_ref = defaultOpen || null) !== null && _ref !== void 0 ? _ref : false);
const subNavRef = React.useRef(null);
const [containsCurrentItem, setContainsCurrentItem] = React.useState(false);
let t1;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t1 = () => {
if (subNavRef.current) {
const currentItem = subNavRef.current.querySelector("[aria-current]:not([aria-current=false])");
if (currentItem) {
setContainsCurrentItem(true);
setIsOpen(true);
}
}
};
$[0] = t1;
} else {
t1 = $[0];
}
let t2;
if ($[1] !== buttonId || $[2] !== subNav) {
t2 = [subNav, buttonId];
$[1] = buttonId;
$[2] = subNav;
$[3] = t2;
} else {
t2 = $[3];
}
useIsomorphicLayoutEffect(t1, t2);
let t3;
if ($[4] !== buttonId || $[5] !== isOpen || $[6] !== subNavId) {
t3 = {
buttonId,
subNavId,
isOpen
};
$[4] = buttonId;
$[5] = isOpen;
$[6] = subNavId;
$[7] = t3;
} else {
t3 = $[7];
}
const t4 = !isOpen && containsCurrentItem;
let t5;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t5 = () => setIsOpen(_temp3);
$[8] = t5;
} else {
t5 = $[8];
}
let t6;
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
t6 = /*#__PURE__*/jsx(ActionList.TrailingVisual, {
children: /*#__PURE__*/jsx(ChevronDownIcon, {
className: classes.ExpandIcon
})
});
$[9] = t6;
} else {
t6 = $[9];
}
let t7;
if ($[10] !== subNav) {
let t8;
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
t8 = {
ref: subNavRef
};
$[12] = t8;
} else {
t8 = $[12];
}
t7 = /*#__PURE__*/React.cloneElement(subNav, t8);
$[10] = subNav;
$[11] = t7;
} else {
t7 = $[11];
}
let t8;
if ($[13] !== t7) {
t8 = /*#__PURE__*/jsx(SubItem, {
children: t7
});
$[13] = t7;
$[14] = t8;
} else {
t8 = $[14];
}
let t9;
if ($[15] !== buttonId || $[16] !== children || $[17] !== isOpen || $[18] !== style || $[19] !== subNavId || $[20] !== t4 || $[21] !== t8) {
t9 = /*#__PURE__*/jsxs(ActionList.Item, {
id: buttonId,
"aria-expanded": isOpen,
"aria-controls": subNavId,
active: t4,
onSelect: t5,
style: style,
children: [children, t6, t8]
});
$[15] = buttonId;
$[16] = children;
$[17] = isOpen;
$[18] = style;
$[19] = subNavId;
$[20] = t4;
$[21] = t8;
$[22] = t9;
} else {
t9 = $[22];
}
let t10;
if ($[23] !== t3 || $[24] !== t9) {
t10 = /*#__PURE__*/jsx(ItemWithSubNavContext.Provider, {
value: t3,
children: t9
});
$[23] = t3;
$[24] = t9;
$[25] = t10;
} else {
t10 = $[25];
}
return t10;
}
// ----------------------------------------------------------------------------
// NavList.SubNav
function _temp3(open) {
return !open;
}
const SubNavContext = /*#__PURE__*/React.createContext({
depth: 0
});
// NOTE: SubNav must be a direct child of an Item
const SubNav = /*#__PURE__*/React.forwardRef((t0, forwardedRef) => {
const $ = c(10);
const {
children
} = t0;
const {
buttonId,
subNavId
} = React.useContext(ItemWithSubNavContext);
const {
depth
} = React.useContext(SubNavContext);
if (!buttonId || !subNavId) {
console.error("NavList.SubNav must be a child of a NavList.Item");
}
if (depth > 3) {
console.error("NavList.SubNav only supports four levels of nesting");
return null;
}
const t1 = depth + 1;
let t2;
if ($[0] !== t1) {
t2 = {
depth: t1
};
$[0] = t1;
$[1] = t2;
} else {
t2 = $[1];
}
let t3;
if ($[2] !== buttonId || $[3] !== children || $[4] !== forwardedRef || $[5] !== subNavId) {
t3 = /*#__PURE__*/jsx("ul", {
className: classes.SubGroup,
id: subNavId,
"aria-labelledby": buttonId,
ref: forwardedRef,
children: children
});
$[2] = buttonId;
$[3] = children;
$[4] = forwardedRef;
$[5] = subNavId;
$[6] = t3;
} else {
t3 = $[6];
}
let t4;
if ($[7] !== t2 || $[8] !== t3) {
t4 = /*#__PURE__*/jsx(SubNavContext.Provider, {
value: t2,
children: t3
});
$[7] = t2;
$[8] = t3;
$[9] = t4;
} else {
t4 = $[9];
}
return t4;
});
SubNav.displayName = 'NavList.SubNav';
// ----------------------------------------------------------------------------
// NavList.LeadingVisual
const LeadingVisual = ActionList.LeadingVisual;
LeadingVisual.displayName = 'NavList.LeadingVisual';
// ----------------------------------------------------------------------------
// NavList.TrailingVisual
const TrailingVisual = ActionList.TrailingVisual;
TrailingVisual.displayName = 'NavList.TrailingVisual';
// ----------------------------------------------------------------------------
// NavList.Divider
const Divider = ActionList.Divider;
Divider.displayName = 'NavList.Divider';
// NavList.TrailingAction
const TrailingAction = ActionList.TrailingAction;
TrailingAction.displayName = 'NavList.TrailingAction';
// ----------------------------------------------------------------------------
// NavList.Group
const Group = t0 => {
const $ = c(11);
let children;
let props;
let title;
if ($[0] !== t0) {
({
title,
children,
...props
} = t0);
$[0] = t0;
$[1] = children;
$[2] = props;
$[3] = title;
} else {
children = $[1];
props = $[2];
title = $[3];
}
let t1;
if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
t1 = /*#__PURE__*/jsx(ActionList.Divider, {});
$[4] = t1;
} else {
t1 = $[4];
}
let t2;
if ($[5] !== title) {
t2 = title ? /*#__PURE__*/jsx(ActionList.GroupHeading, {
as: "h3",
"data-component": "ActionList.GroupHeading",
children: title
}) : null;
$[5] = title;
$[6] = t2;
} else {
t2 = $[6];
}
let t3;
if ($[7] !== children || $[8] !== props || $[9] !== t2) {
t3 = /*#__PURE__*/jsxs(Fragment, {
children: [t1, /*#__PURE__*/jsxs(ActionList.Group, {
...props,
children: [t2, children]
})]
});
$[7] = children;
$[8] = props;
$[9] = t2;
$[10] = t3;
} else {
t3 = $[10];
}
return t3;
};
// ----------------------------------------------------------------------------
// NavList.GroupExpand
const GroupExpand = /*#__PURE__*/React.forwardRef((t0, forwardedRef) => {
const $ = c(23);
let items;
let props;
let renderItem;
let t1;
let t2;
if ($[0] !== t0) {
({
label: t1,
pages: t2,
items,
renderItem,
...props
} = t0);
$[0] = t0;
$[1] = items;
$[2] = props;
$[3] = renderItem;
$[4] = t1;
$[5] = t2;
} else {
items = $[1];
props = $[2];
renderItem = $[3];
t1 = $[4];
t2 = $[5];
}
const label = t1 === undefined ? "Show more" : t1;
const pages = t2 === undefined ? 0 : t2;
const [currentPage, setCurrentPage] = React.useState(0);
const groupId = useId();
const itemsPerPage = items.length / pages;
const amountToShow = pages === 0 ? items.length : Math.ceil(itemsPerPage * currentPage);
const focusTargetIndex = currentPage === 1 ? 0 : amountToShow - Math.floor(itemsPerPage);
let t3;
if ($[6] !== amountToShow || $[7] !== currentPage || $[8] !== focusTargetIndex || $[9] !== groupId || $[10] !== items || $[11] !== renderItem) {
t3 = currentPage > 0 ? /*#__PURE__*/jsx(Fragment, {
children: items.map((itemArr, index) => {
const {
text,
trailingVisual: TrailingVisualIcon,
leadingVisual: LeadingVisualIcon,
trailingAction,
...rest
} = itemArr;
const {
icon,
label: actionLabel,
...actionProps
} = trailingAction || {};
const focusTarget = index === focusTargetIndex ? groupId : undefined;
if (index < amountToShow) {
if (renderItem) {
return renderItem({
...itemArr,
"data-expand-focus-target": focusTarget
});
}
return /*#__PURE__*/createElement(Item, {
...rest,
key: index,
"data-expand-focus-target": focusTarget
}, LeadingVisualIcon ? /*#__PURE__*/jsx(LeadingVisual, {
children: /*#__PURE__*/jsx(LeadingVisualIcon, {})
}) : null, text, TrailingVisualIcon ? /*#__PURE__*/jsx(TrailingVisual, {
children: /*#__PURE__*/jsx(TrailingVisualIcon, {})
}) : null, trailingAction ? /*#__PURE__*/jsx(TrailingAction, {
...actionProps,
icon: icon,
label: actionLabel || ""
}) : null);
}
})
}) : null;
$[6] = amountToShow;
$[7] = currentPage;
$[8] = focusTargetIndex;
$[9] = groupId;
$[10] = items;
$[11] = renderItem;
$[12] = t3;
} else {
t3 = $[12];
}
let t4;
if ($[13] !== currentPage || $[14] !== forwardedRef || $[15] !== groupId || $[16] !== label || $[17] !== pages || $[18] !== props) {
t4 = currentPage < pages || currentPage === 0 ? /*#__PURE__*/jsxs(ActionList.Item, {
as: "button",
"aria-expanded": "false",
ref: forwardedRef,
onSelect: () => {
flushSync(() => {
setCurrentPage(currentPage + 1);
});
const focusTarget_0 = Array.from(document.querySelectorAll(`[data-expand-focus-target="${groupId}"]`));
if (focusTarget_0.length > 0) {
focusTarget_0[focusTarget_0.length - 1].focus();
}
},
...props,
children: [label, /*#__PURE__*/jsx(TrailingVisual, {
children: /*#__PURE__*/jsx(PlusIcon, {})
})]
}) : null;
$[13] = currentPage;
$[14] = forwardedRef;
$[15] = groupId;
$[16] = label;
$[17] = pages;
$[18] = props;
$[19] = t4;
} else {
t4 = $[19];
}
let t5;
if ($[20] !== t3 || $[21] !== t4) {
t5 = /*#__PURE__*/jsxs(Fragment, {
children: [t3, t4]
});
$[20] = t3;
$[21] = t4;
$[22] = t5;
} else {
t5 = $[22];
}
return t5;
});
// ----------------------------------------------------------------------------
// NavList.GroupHeading
/**
* This is an alternative to the `title` prop on `NavList.Group`.
* It was primarily added to allow links in group headings.
*/
const GroupHeading = t0 => {
const $ = c(10);
let className;
let rest;
let t1;
if ($[0] !== t0) {
({
as: t1,
className,
...rest
} = t0);
$[0] = t0;
$[1] = className;
$[2] = rest;
$[3] = t1;
} else {
className = $[1];
rest = $[2];
t1 = $[3];
}
const as = t1 === undefined ? "h3" : t1;
let t2;
if ($[4] !== className) {
t2 = clsx(navListClasses.GroupHeading, className);
$[4] = className;
$[5] = t2;
} else {
t2 = $[5];
}
let t3;
if ($[6] !== as || $[7] !== rest || $[8] !== t2) {
t3 = /*#__PURE__*/jsx(ActionList.GroupHeading, {
as: as,
className: t2,
"data-component": "NavList.GroupHeading",
headingWrapElement: "li",
...rest
});
$[6] = as;
$[7] = rest;
$[8] = t2;
$[9] = t3;
} else {
t3 = $[9];
}
return t3;
};
// ----------------------------------------------------------------------------
// Export
const NavList = Object.assign(Root, {
Description: ActionList.Description,
Item,
SubNav,
LeadingVisual,
TrailingVisual,
TrailingAction,
Divider,
Group,
GroupExpand,
GroupHeading
});
function _temp(child) {
return /*#__PURE__*/isValidElement(child) && (child.type === SubNav || isSlot(child, SubNav));
}
function _temp2(child_0) {
return /*#__PURE__*/isValidElement(child_0) ? child_0.type !== SubNav && child_0.type !== TrailingAction && !isSlot(child_0, SubNav) && !isSlot(child_0, TrailingAction) : true;
}
export { GroupExpand, NavList };