@primer/react
Version:
An implementation of GitHub's Primer Design System using React
505 lines (504 loc) • 15.3 kB
JavaScript
import { useOnOutsideClick } from "../hooks/useOnOutsideClick.js";
import { useOnEscapePress } from "../hooks/useOnEscapePress.js";
import useIsomorphicLayoutEffect from "../utils/useIsomorphicLayoutEffect.js";
import { useResizeObserver } from "../hooks/useResizeObserver.js";
import { fixedForwardRef } from "../utils/modern-polymorphic.js";
import { IconButton } from "../Button/IconButton.js";
import { ActionList } from "../ActionList/index.js";
import Breadcrumbs_module_css_default from "./Breadcrumbs.module.css.js";
import Details from "../Details/Details.js";
import { c } from "react-compiler-runtime";
import { clsx } from "clsx";
import { jsx, jsxs } from "react/jsx-runtime";
import React, { useRef, useState } from "react";
import { KebabHorizontalIcon } from "@primer/octicons-react";
//#region src/Breadcrumbs/Breadcrumbs.tsx
const BreadcrumbsList = (t0) => {
const $ = c(2);
const { children } = t0;
let t1;
if ($[0] !== children) {
t1 = /*#__PURE__*/ jsx("ol", {
className: Breadcrumbs_module_css_default.BreadcrumbsList,
children
});
$[0] = children;
$[1] = t1;
} else t1 = $[1];
return t1;
};
const BreadcrumbsMenuItem = /*#__PURE__*/ React.forwardRef((t0, menuRefCallback) => {
const $ = c(25);
let ariaLabel;
let items;
let rest;
if ($[0] !== t0) {
({items, "aria-label": ariaLabel, ...rest} = t0);
$[0] = t0;
$[1] = ariaLabel;
$[2] = items;
$[3] = rest;
} else {
ariaLabel = $[1];
items = $[2];
rest = $[3];
}
const [isOpen, setIsOpen] = useState(false);
const detailsRef = useRef(null);
const menuButtonRef = useRef(null);
const menuContainerRef = useRef(null);
let t1;
if ($[4] !== menuRefCallback) {
t1 = (element) => {
detailsRef.current = element;
if (typeof menuRefCallback === "function") menuRefCallback(element);
};
$[4] = menuRefCallback;
$[5] = t1;
} else t1 = $[5];
const detailsRefCallback = t1;
let t2;
if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
t2 = (event) => {
event.preventDefault();
if (detailsRef.current) {
const newOpenState = !detailsRef.current.open;
detailsRef.current.open = newOpenState;
setIsOpen(newOpenState);
}
};
$[6] = t2;
} else t2 = $[6];
const handleSummaryClick = t2;
let t3;
if ($[7] === Symbol.for("react.memo_cache_sentinel")) {
t3 = () => {
if (detailsRef.current) {
detailsRef.current.open = false;
setIsOpen(false);
}
};
$[7] = t3;
} else t3 = $[7];
const closeOverlay = t3;
let t4;
if ($[8] === Symbol.for("react.memo_cache_sentinel")) {
t4 = () => {
var _menuButtonRef$curren;
(_menuButtonRef$curren = menuButtonRef.current) === null || _menuButtonRef$curren === void 0 || _menuButtonRef$curren.focus();
};
$[8] = t4;
} else t4 = $[8];
const focusOnMenuButton = t4;
let t5;
let t6;
if ($[9] !== isOpen) {
t5 = (event_0) => {
if (isOpen) {
event_0.preventDefault();
closeOverlay();
focusOnMenuButton();
}
};
t6 = [isOpen];
$[9] = isOpen;
$[10] = t5;
$[11] = t6;
} else {
t5 = $[10];
t6 = $[11];
}
useOnEscapePress(t5, t6);
let t7;
if ($[12] === Symbol.for("react.memo_cache_sentinel")) {
t7 = {
onClickOutside: closeOverlay,
containerRef: menuContainerRef,
ignoreClickRefs: [menuButtonRef]
};
$[12] = t7;
} else t7 = $[12];
useOnOutsideClick(t7);
const t8 = ariaLabel || `${items.length} more breadcrumb items`;
const t9 = isOpen ? "true" : "false";
let t10;
if ($[13] !== rest || $[14] !== t8 || $[15] !== t9) {
t10 = /*#__PURE__*/ jsx(IconButton, {
as: "summary",
role: "button",
ref: menuButtonRef,
"aria-label": t8,
"aria-expanded": t9,
onClick: handleSummaryClick,
variant: "invisible",
size: "small",
icon: KebabHorizontalIcon,
tooltipDirection: "e",
...rest
});
$[13] = rest;
$[14] = t8;
$[15] = t9;
$[16] = t10;
} else t10 = $[16];
let t11;
if ($[17] !== items) {
t11 = items.map(_temp);
$[17] = items;
$[18] = t11;
} else t11 = $[18];
let t12;
if ($[19] !== t11) {
t12 = /*#__PURE__*/ jsx("div", {
ref: menuContainerRef,
className: Breadcrumbs_module_css_default.MenuOverlay,
children: /*#__PURE__*/ jsx(ActionList, { children: t11 })
});
$[19] = t11;
$[20] = t12;
} else t12 = $[20];
let t13;
if ($[21] !== detailsRefCallback || $[22] !== t10 || $[23] !== t12) {
t13 = /*#__PURE__*/ jsxs(Details, {
ref: detailsRefCallback,
className: Breadcrumbs_module_css_default.MenuDetails,
"data-component": "Breadcrumbs.MenuItem",
children: [t10, t12]
});
$[21] = detailsRefCallback;
$[22] = t10;
$[23] = t12;
$[24] = t13;
} else t13 = $[24];
return t13;
});
BreadcrumbsMenuItem.displayName = "Breadcrumbs.MenuItem";
const getValidChildren = (children) => {
return React.Children.toArray(children).filter((child) => /*#__PURE__*/ React.isValidElement(child));
};
const MENU_BUTTON_FALLBACK_WIDTH = 32;
const CONTAINER_FALLBACK_WIDTH = 800;
function calculateOverflow({ availableWidth, itemCount, childArrayWidths, menuButtonWidth, overflow, hideRoot }) {
var _childArrayWidths$;
let eHideRoot = hideRoot;
const rootItemWidth = (_childArrayWidths$ = childArrayWidths[0]) !== null && _childArrayWidths$ !== void 0 ? _childArrayWidths$ : 0;
const isNarrow = availableWidth < 544;
let MIN_VISIBLE_ITEMS = 4;
if (!eHideRoot) MIN_VISIBLE_ITEMS = 3;
else if (isNarrow && itemCount > 2) MIN_VISIBLE_ITEMS = 1;
const calculateVisibleItemsWidth = (w) => {
const widths = w.reduce((sum, width) => sum + width + 16, 0);
return !eHideRoot ? rootItemWidth + widths : widths;
};
let currentVisibleItemWidths = [...childArrayWidths];
let menuItemCount = 0;
if (availableWidth > 0 && currentVisibleItemWidths.length > 0) {
let visibleItemsWidthTotal = calculateVisibleItemsWidth(currentVisibleItemWidths);
while ((overflow === "menu" || overflow === "menu-with-root") && (visibleItemsWidthTotal > availableWidth || currentVisibleItemWidths.length > MIN_VISIBLE_ITEMS)) {
menuItemCount += 1;
currentVisibleItemWidths = currentVisibleItemWidths.slice(1);
visibleItemsWidthTotal = calculateVisibleItemsWidth(currentVisibleItemWidths) + menuButtonWidth;
if (currentVisibleItemWidths.length === 1 && visibleItemsWidthTotal > availableWidth) {
eHideRoot = true;
break;
} else eHideRoot = hideRoot;
}
}
return {
menuItemCount,
effectiveHideRoot: eHideRoot
};
}
function Breadcrumbs(t0) {
const $ = c(48);
const { className, children, style, overflow: t1, variant: t2 } = t0;
const overflow = t1 === void 0 ? "wrap" : t1;
const variant = t2 === void 0 ? "normal" : t2;
const containerRef = useRef(null);
const hideRoot = !(overflow === "menu-with-root");
let t3;
if ($[0] !== children) {
t3 = getValidChildren(children);
$[0] = children;
$[1] = t3;
} else t3 = $[1];
const childArray = t3;
const rootItem = childArray[0];
const [childArrayWidths, setChildArrayWidths] = useState(_temp2);
const [containerWidth, setContainerWidth] = useState(null);
const [menuButtonWidth, setMenuButtonWidth] = useState(MENU_BUTTON_FALLBACK_WIDTH);
let t4;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t4 = (element) => {
if (element) {
const iconButtonElement = element.querySelector("button[data-component=\"IconButton\"]");
if (iconButtonElement) {
const measuredWidth = iconButtonElement.offsetWidth;
setMenuButtonWidth((prev) => prev === measuredWidth ? prev : measuredWidth);
}
}
};
$[2] = t4;
} else t4 = $[2];
const measureMenuButton = t4;
let t5;
if ($[3] !== childArray.length || $[4] !== overflow) {
t5 = () => {
if (overflow === "wrap") return;
const containerElement = containerRef.current;
if (!containerElement) return;
const measuredContainerWidth = containerElement.offsetWidth;
setContainerWidth((prev_0) => prev_0 === measuredContainerWidth ? prev_0 : measuredContainerWidth);
const listElement = containerElement.querySelector("ol");
if (listElement && listElement.children.length > 0 && listElement.children.length === childArray.length) setChildArrayWidths(Array.from(listElement.children).map(_temp3));
};
$[3] = childArray.length;
$[4] = overflow;
$[5] = t5;
} else t5 = $[5];
let t6;
if ($[6] !== childArray || $[7] !== overflow) {
t6 = [childArray, overflow];
$[6] = childArray;
$[7] = overflow;
$[8] = t6;
} else t6 = $[8];
useIsomorphicLayoutEffect(t5, t6);
let t7;
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
t7 = (entries) => {
if (entries[0]) {
const width = Math.round(entries[0].contentRect.width);
setContainerWidth((prev_1) => prev_1 === width ? prev_1 : width);
}
};
$[9] = t7;
} else t7 = $[9];
let t8;
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
t8 = [];
$[10] = t8;
} else t8 = $[10];
useResizeObserver(t7, containerRef, t8, overflow !== "wrap");
let t9;
bb0: {
if (overflow === "wrap" || childArrayWidths.length !== childArray.length) {
let t10;
if ($[11] !== hideRoot) {
t10 = {
menuItemCount: 0,
effectiveHideRoot: hideRoot
};
$[11] = hideRoot;
$[12] = t10;
} else t10 = $[12];
t9 = t10;
break bb0;
}
const t10 = containerWidth !== null && containerWidth !== void 0 ? containerWidth : CONTAINER_FALLBACK_WIDTH;
let t11;
if ($[13] !== childArray.length || $[14] !== childArrayWidths || $[15] !== hideRoot || $[16] !== menuButtonWidth || $[17] !== overflow || $[18] !== t10) {
t11 = calculateOverflow({
availableWidth: t10,
itemCount: childArray.length,
childArrayWidths,
menuButtonWidth,
overflow,
hideRoot
});
$[13] = childArray.length;
$[14] = childArrayWidths;
$[15] = hideRoot;
$[16] = menuButtonWidth;
$[17] = overflow;
$[18] = t10;
$[19] = t11;
} else t11 = $[19];
t9 = t11;
}
const { menuItemCount, effectiveHideRoot } = t9;
let t10;
if ($[20] !== childArray || $[21] !== children || $[22] !== effectiveHideRoot || $[23] !== menuItemCount || $[24] !== overflow || $[25] !== rootItem) {
bb1: {
if (overflow === "wrap" || menuItemCount === 0) {
let t11;
if ($[27] !== children) {
t11 = React.Children.map(children, _temp4);
$[27] = children;
$[28] = t11;
} else t11 = $[28];
t10 = t11;
break bb1;
}
const menuItems = childArray.slice(0, menuItemCount);
const visibleItems = childArray.slice(menuItemCount);
const effectiveMenuItems = effectiveHideRoot ? menuItems : menuItems.slice(1);
const t11 = `${effectiveMenuItems.length} more breadcrumb items`;
let t12;
if ($[29] !== effectiveMenuItems || $[30] !== t11) {
t12 = /*#__PURE__*/ jsx(BreadcrumbsMenuItem, {
ref: measureMenuButton,
items: effectiveMenuItems,
"aria-label": t11
});
$[29] = effectiveMenuItems;
$[30] = t11;
$[31] = t12;
} else t12 = $[31];
let t13;
if ($[32] === Symbol.for("react.memo_cache_sentinel")) {
t13 = /*#__PURE__*/ jsx(ItemSeparator, {});
$[32] = t13;
} else t13 = $[32];
let t14;
if ($[33] !== t12) {
t14 = /*#__PURE__*/ jsxs("li", {
className: Breadcrumbs_module_css_default.BreadcrumbsItem,
children: [t12, t13]
}, "breadcrumbs-menu");
$[33] = t12;
$[34] = t14;
} else t14 = $[34];
const menuElement = t14;
const visibleElements = visibleItems.map(_temp5);
let t15;
if ($[35] === Symbol.for("react.memo_cache_sentinel")) {
t15 = /*#__PURE__*/ jsx(ItemSeparator, {});
$[35] = t15;
} else t15 = $[35];
let t16;
if ($[36] !== rootItem) {
t16 = /*#__PURE__*/ jsxs("li", {
className: Breadcrumbs_module_css_default.BreadcrumbsItem,
children: [rootItem, t15]
}, "rootElement");
$[36] = rootItem;
$[37] = t16;
} else t16 = $[37];
const rootElement = t16;
if (effectiveHideRoot) t10 = [menuElement, ...visibleElements];
else t10 = [
rootElement,
menuElement,
...visibleElements
];
}
$[20] = childArray;
$[21] = children;
$[22] = effectiveHideRoot;
$[23] = menuItemCount;
$[24] = overflow;
$[25] = rootItem;
$[26] = t10;
} else t10 = $[26];
const finalChildren = t10;
let t11;
if ($[38] !== className) {
t11 = clsx(className, Breadcrumbs_module_css_default.BreadcrumbsBase);
$[38] = className;
$[39] = t11;
} else t11 = $[39];
let t12;
if ($[40] !== finalChildren) {
t12 = /*#__PURE__*/ jsx(BreadcrumbsList, { children: finalChildren });
$[40] = finalChildren;
$[41] = t12;
} else t12 = $[41];
let t13;
if ($[42] !== overflow || $[43] !== style || $[44] !== t11 || $[45] !== t12 || $[46] !== variant) {
t13 = /*#__PURE__*/ jsx("nav", {
className: t11,
"aria-label": "Breadcrumbs",
style,
ref: containerRef,
"data-overflow": overflow,
"data-variant": variant,
"data-component": "Breadcrumbs",
children: t12
});
$[42] = overflow;
$[43] = style;
$[44] = t11;
$[45] = t12;
$[46] = variant;
$[47] = t13;
} else t13 = $[47];
return t13;
}
function _temp5(child_1, index) {
return /*#__PURE__*/ jsxs("li", {
className: Breadcrumbs_module_css_default.BreadcrumbsItem,
children: [child_1, /*#__PURE__*/ jsx(ItemSeparator, {})]
}, `visible + ${index}`);
}
_temp5.displayName = "_temp5";
function _temp4(child_0) {
return /*#__PURE__*/ jsx("li", {
className: Breadcrumbs_module_css_default.ItemWrapper,
children: child_0
});
}
_temp4.displayName = "_temp4";
function _temp3(child) {
return child.offsetWidth;
}
function _temp2() {
return [];
}
const ItemSeparator = () => {
const $ = c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = /*#__PURE__*/ jsx("span", {
className: Breadcrumbs_module_css_default.ItemSeparator,
children: /*#__PURE__*/ jsx("svg", {
width: "16",
height: "16",
viewBox: "0 0 16 16",
xmlns: "http://www.w3.org/2000/svg",
"aria-hidden": "true",
children: /*#__PURE__*/ jsx("path", {
d: "M10.956 1.27994L6.06418 14.7201L5 14.7201L9.89181 1.27994L10.956 1.27994Z",
fill: "currentcolor"
})
})
});
$[0] = t0;
} else t0 = $[0];
return t0;
};
const BreadcrumbsItem = fixedForwardRef((props, ref) => {
const { as: Component = "a", selected, className, ...rest } = props;
return /*#__PURE__*/ jsx(Component, {
className: clsx(className, Breadcrumbs_module_css_default.Item, selected && "selected"),
"aria-current": selected ? "page" : void 0,
ref,
"data-component": "Breadcrumbs.Item",
...rest
});
});
Breadcrumbs.displayName = "Breadcrumbs";
const BreadcrumbsItemWithDisplayName = Object.assign(BreadcrumbsItem, { displayName: "Breadcrumbs.Item" });
var Breadcrumbs_default = Object.assign(Breadcrumbs, { Item: BreadcrumbsItemWithDisplayName });
/**
* @deprecated Use the `Breadcrumbs` component instead (i.e. `<Breadcrumb>` → `<Breadcrumbs>`)
*/
const Breadcrumb = Object.assign(Breadcrumbs, { Item: BreadcrumbsItem });
/**
* @deprecated Use the `BreadcrumbsProps` type instead
*/
/**
* @deprecated Use the `BreadcrumbsItemProps` type instead
*/
function _temp(item, index) {
const { children, selected, as: Component, ...itemProps } = item.props;
return /*#__PURE__*/ jsx(ActionList.LinkItem, {
as: Component,
...itemProps,
"aria-current": selected ? "page" : void 0,
children
}, index);
}
_temp.displayName = "_temp";
//#endregion
export { Breadcrumb, Breadcrumbs_default as default };