UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

505 lines (504 loc) 15.3 kB
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 };