UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

542 lines (541 loc) • 16.8 kB
import { useMergedRefs } from "../hooks/useMergedRefs.js"; import { IconButton } from "../Button/IconButton.js"; import { ButtonComponent } from "../Button/Button.js"; import { FocusKeys, useFocusZone } from "../hooks/useFocusZone.js"; import { ActionList } from "../ActionList/index.js"; import { ActionMenu } from "../ActionMenu/ActionMenu.js"; import { createDescendantRegistry } from "../utils/descendant-registry.js"; import ActionBar_module_css_default from "./ActionBar.module.css.js"; import { c } from "react-compiler-runtime"; import { clsx } from "clsx"; import { jsx, jsxs } from "react/jsx-runtime"; import React, { forwardRef, useCallback, useContext, useMemo, useRef, useState, useSyncExternalStore } from "react"; import { KebabHorizontalIcon } from "@primer/octicons-react"; //#region src/ActionBar/ActionBar.tsx const ActionBarContext = /*#__PURE__*/ React.createContext({ size: "medium" }); const ActionBarItemsRegistry = createDescendantRegistry(); const FOCUSABLE_ITEM_SELECTOR = ":is(button, a, input, [tabindex]):not(:disabled):not([data-overflowing]):not([data-more-button-inactive])"; const renderMenuItem = (item, index) => { if (item.type === "divider") return /*#__PURE__*/ jsx(ActionList.Divider, {}, index); const { label, onClick, disabled, trailingVisual: TrailingIcon, leadingVisual: LeadingIcon, items, variant } = item; if (items && items.length > 0) return /*#__PURE__*/ jsxs(ActionMenu, { children: [/*#__PURE__*/ jsx(ActionMenu.Anchor, { children: /*#__PURE__*/ jsxs(ActionList.Item, { disabled, variant, children: [ LeadingIcon ? /*#__PURE__*/ jsx(ActionList.LeadingVisual, { children: /*#__PURE__*/ jsx(LeadingIcon, {}) }) : null, label, TrailingIcon ? /*#__PURE__*/ jsx(ActionList.TrailingVisual, { children: typeof TrailingIcon === "string" ? /*#__PURE__*/ jsx("span", { children: TrailingIcon }) : /*#__PURE__*/ jsx(TrailingIcon, {}) }) : null ] }) }), /*#__PURE__*/ jsx(ActionMenu.Overlay, { children: /*#__PURE__*/ jsx(ActionList, { children: items.map((subItem, subIndex) => renderMenuItem(subItem, subIndex)) }) })] }, label); return /*#__PURE__*/ jsxs(ActionList.Item, { onSelect: onClick, disabled, variant, children: [ LeadingIcon ? /*#__PURE__*/ jsx(ActionList.LeadingVisual, { children: /*#__PURE__*/ jsx(LeadingIcon, {}) }) : null, label, TrailingIcon ? /*#__PURE__*/ jsx(ActionList.TrailingVisual, { children: typeof TrailingIcon === "string" ? /*#__PURE__*/ jsx("span", { children: TrailingIcon }) : /*#__PURE__*/ jsx(TrailingIcon, {}) }) : null ] }, label); }; renderMenuItem.displayName = "renderMenuItem"; const ActionBar = (t0) => { const $ = c(40); const { size: t1, children, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, flush: t2, className, gap: t3 } = t0; const size = t1 === void 0 ? "medium" : t1; const flush = t2 === void 0 ? false : t2; const gap = t3 === void 0 ? "condensed" : t3; const [childRegistry, setChildRegistry] = ActionBarItemsRegistry.useRegistryState(); let t4; if ($[0] !== childRegistry) { t4 = childRegistry && Array.from(childRegistry.entries()).filter(_temp); $[0] = childRegistry; $[1] = t4; } else t4 = $[1]; const overflowItems = t4; let t5; if ($[2] === Symbol.for("react.memo_cache_sentinel")) { t5 = { bindKeys: FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd, focusOutBehavior: "wrap", focusableElementFilter: _temp2 }; $[2] = t5; } else t5 = $[2]; let t6; if ($[3] !== overflowItems) { t6 = [overflowItems]; $[3] = overflowItems; $[4] = t6; } else t6 = $[4]; const { containerRef } = useFocusZone(t5, t6); let t7; if ($[5] !== size) { t7 = { size }; $[5] = size; $[6] = t7; } else t7 = $[6]; let t8; if ($[7] !== className) { t8 = clsx(className, ActionBar_module_css_default.Nav); $[7] = className; $[8] = t8; } else t8 = $[8]; const t9 = containerRef; const t10 = overflowItems ? overflowItems.length > 0 : void 0; let t11; if ($[9] === Symbol.for("react.memo_cache_sentinel")) { t11 = /*#__PURE__*/ jsx("div", { className: ActionBar_module_css_default.OverflowSpacer }); $[9] = t11; } else t11 = $[9]; let t12; if ($[10] !== children || $[11] !== setChildRegistry) { t12 = /*#__PURE__*/ jsxs("div", { className: ActionBar_module_css_default.OverflowContainer, children: [t11, /*#__PURE__*/ jsx(ActionBarItemsRegistry.Provider, { setRegistry: setChildRegistry, children })] }); $[10] = children; $[11] = setChildRegistry; $[12] = t12; } else t12 = $[12]; const t13 = `More ${ariaLabel} items ${overflowItems === null || overflowItems === void 0 ? void 0 : overflowItems.length}`; const t14 = overflowItems !== null && overflowItems !== void 0 && overflowItems.length ? void 0 : true; let t15; if ($[13] !== size || $[14] !== t13 || $[15] !== t14) { t15 = /*#__PURE__*/ jsx(ActionMenu.Anchor, { children: /*#__PURE__*/ jsx(IconButton, { variant: "invisible", "aria-label": t13, icon: KebabHorizontalIcon, className: ActionBar_module_css_default.MoreButton, "data-more-button-inactive": t14, size }) }); $[13] = size; $[14] = t13; $[15] = t14; $[16] = t15; } else t15 = $[16]; let t16; if ($[17] !== overflowItems) { t16 = overflowItems === null || overflowItems === void 0 ? void 0 : overflowItems.map(_temp4); $[17] = overflowItems; $[18] = t16; } else t16 = $[18]; let t17; if ($[19] !== t16) { t17 = /*#__PURE__*/ jsx(ActionMenu.Overlay, { children: /*#__PURE__*/ jsx(ActionList, { children: t16 }) }); $[19] = t16; $[20] = t17; } else t17 = $[20]; let t18; if ($[21] !== t15 || $[22] !== t17) { t18 = /*#__PURE__*/ jsxs(ActionMenu, { children: [t15, t17] }); $[21] = t15; $[22] = t17; $[23] = t18; } else t18 = $[23]; let t19; if ($[24] !== ariaLabel || $[25] !== ariaLabelledBy || $[26] !== gap || $[27] !== size || $[28] !== t10 || $[29] !== t12 || $[30] !== t18 || $[31] !== t9) { t19 = /*#__PURE__*/ jsxs("div", { ref: t9, role: "toolbar", className: ActionBar_module_css_default.List, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "data-gap": gap, "data-size": size, "data-has-overflow": t10, children: [t12, t18] }); $[24] = ariaLabel; $[25] = ariaLabelledBy; $[26] = gap; $[27] = size; $[28] = t10; $[29] = t12; $[30] = t18; $[31] = t9; $[32] = t19; } else t19 = $[32]; let t20; if ($[33] !== flush || $[34] !== t19 || $[35] !== t8) { t20 = /*#__PURE__*/ jsx("div", { className: t8, "data-component": "ActionBar", "data-flush": flush, children: t19 }); $[33] = flush; $[34] = t19; $[35] = t8; $[36] = t20; } else t20 = $[36]; let t21; if ($[37] !== t20 || $[38] !== t7) { t21 = /*#__PURE__*/ jsx(ActionBarContext.Provider, { value: t7, children: t20 }); $[37] = t20; $[38] = t7; $[39] = t21; } else t21 = $[39]; return t21; }; function useActionBarItem(ref, registryProps) { var _useContext; const $ = c(8); const isGroupOverflowing = (_useContext = useContext(ActionBarGroupContext)) === null || _useContext === void 0 ? void 0 : _useContext.isOverflowing; const isInGroup = isGroupOverflowing !== void 0; let t0; if ($[0] !== isInGroup || $[1] !== ref) { t0 = (onChange) => { if (isInGroup) return _temp5; const observer = new IntersectionObserver(() => onChange(), { threshold: .75 }); if (ref.current) observer.observe(ref.current); return () => observer.disconnect(); }; $[0] = isInGroup; $[1] = ref; $[2] = t0; } else t0 = $[2]; const subscribeIntersectionObserver = t0; let t1; if ($[3] !== ref) { t1 = () => ref.current ? ref.current.offsetTop > 0 : false; $[3] = ref; $[4] = t1; } else t1 = $[4]; const isItemOverflowing = useSyncExternalStore(subscribeIntersectionObserver, t1, _temp6); const isOverflowing = isGroupOverflowing || isItemOverflowing; ActionBarItemsRegistry.useRegisterDescendant(isOverflowing ? registryProps : null); const t2 = isOverflowing ? "" : void 0; let t3; if ($[5] !== isOverflowing || $[6] !== t2) { t3 = { isOverflowing, dataOverflowingAttr: t2 }; $[5] = isOverflowing; $[6] = t2; $[7] = t3; } else t3 = $[7]; return t3; } function _temp6() { return false; } function _temp5() {} const ActionBarIconButton = /*#__PURE__*/ forwardRef(({ disabled, onClick, ...props }, forwardedRef) => { const ref = useRef(null); const mergedRef = useMergedRefs(forwardedRef, ref); const { size } = React.useContext(ActionBarContext); const { ["aria-label"]: ariaLabel, icon } = props; const { dataOverflowingAttr } = useActionBarItem(ref, useMemo(() => ({ type: "action", label: ariaLabel !== null && ariaLabel !== void 0 ? ariaLabel : "", icon, disabled: !!disabled, onClick }), [ ariaLabel, icon, disabled, onClick ])); return /*#__PURE__*/ jsx(IconButton, { "aria-disabled": disabled, ref: mergedRef, size, onClick: useCallback((event) => { if (disabled) return; onClick === null || onClick === void 0 || onClick(event); }, [disabled, onClick]), ...props, variant: "invisible", "data-overflowing": dataOverflowingAttr }); }); const ActionBarButton = /*#__PURE__*/ forwardRef((t0, forwardedRef) => { const $ = c(19); let disabled; let onClick; let props; if ($[0] !== t0) { ({disabled, onClick, ...props} = t0); $[0] = t0; $[1] = disabled; $[2] = onClick; $[3] = props; } else { disabled = $[1]; onClick = $[2]; props = $[3]; } const ref = useRef(null); const mergedRef = useMergedRefs(forwardedRef, ref); const { size } = React.useContext(ActionBarContext); const { children, leadingVisual } = props; const t1 = typeof leadingVisual === "function" ? leadingVisual : void 0; const t2 = !!disabled; const t3 = onClick; let t4; if ($[4] !== children || $[5] !== t1 || $[6] !== t2 || $[7] !== t3) { t4 = { type: "action", label: children, icon: t1, disabled: t2, onClick: t3 }; $[4] = children; $[5] = t1; $[6] = t2; $[7] = t3; $[8] = t4; } else t4 = $[8]; const { dataOverflowingAttr } = useActionBarItem(ref, t4); let t5; if ($[9] !== disabled || $[10] !== onClick) { t5 = (event) => { var _onClick; if (disabled) return; (_onClick = onClick) === null || _onClick === void 0 || _onClick(event); }; $[9] = disabled; $[10] = onClick; $[11] = t5; } else t5 = $[11]; const clickHandler = t5; let t6; if ($[12] !== clickHandler || $[13] !== dataOverflowingAttr || $[14] !== disabled || $[15] !== mergedRef || $[16] !== props || $[17] !== size) { t6 = /*#__PURE__*/ jsx(ButtonComponent, { "aria-disabled": disabled, ref: mergedRef, size, onClick: clickHandler, ...props, variant: "invisible", "data-overflowing": dataOverflowingAttr }); $[12] = clickHandler; $[13] = dataOverflowingAttr; $[14] = disabled; $[15] = mergedRef; $[16] = props; $[17] = size; $[18] = t6; } else t6 = $[18]; return t6; }); const ActionBarGroupContext = /*#__PURE__*/ React.createContext(null); const ActionBarGroup = /*#__PURE__*/ forwardRef((t0, forwardedRef) => { const $ = c(10); const { children } = t0; const backupRef = useRef(null); const ref = forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : backupRef; let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = { type: "group" }; $[0] = t1; } else t1 = $[0]; const { dataOverflowingAttr, isOverflowing } = useActionBarItem(ref, t1); let t2; if ($[1] !== isOverflowing) { t2 = { isOverflowing }; $[1] = isOverflowing; $[2] = t2; } else t2 = $[2]; let t3; if ($[3] !== children || $[4] !== dataOverflowingAttr || $[5] !== ref) { t3 = /*#__PURE__*/ jsx("div", { className: ActionBar_module_css_default.Group, "data-component": "ActionBar.Group", ref, "data-overflowing": dataOverflowingAttr, children }); $[3] = children; $[4] = dataOverflowingAttr; $[5] = ref; $[6] = t3; } else t3 = $[6]; let t4; if ($[7] !== t2 || $[8] !== t3) { t4 = /*#__PURE__*/ jsx(ActionBarGroupContext.Provider, { value: t2, children: t3 }); $[7] = t2; $[8] = t3; $[9] = t4; } else t4 = $[9]; return t4; }); const ActionBarMenu = /*#__PURE__*/ forwardRef((t0, forwardedRef) => { const $ = c(31); let ariaLabel; let icon; let items; let overflowIcon; let props; let returnFocusRef; if ($[0] !== t0) { ({"aria-label": ariaLabel, icon, overflowIcon, items, returnFocusRef, ...props} = t0); $[0] = t0; $[1] = ariaLabel; $[2] = icon; $[3] = items; $[4] = overflowIcon; $[5] = props; $[6] = returnFocusRef; } else { ariaLabel = $[1]; icon = $[2]; items = $[3]; overflowIcon = $[4]; props = $[5]; returnFocusRef = $[6]; } const backupRef = useRef(null); const ref = forwardedRef !== null && forwardedRef !== void 0 ? forwardedRef : backupRef; const [menuOpen, setMenuOpen] = useState(false); const t1 = overflowIcon ? overflowIcon : icon; let t2; if ($[7] !== ariaLabel || $[8] !== items || $[9] !== returnFocusRef || $[10] !== t1) { t2 = { type: "menu", label: ariaLabel, icon: t1, returnFocusRef, items }; $[7] = ariaLabel; $[8] = items; $[9] = returnFocusRef; $[10] = t1; $[11] = t2; } else t2 = $[11]; const { dataOverflowingAttr } = useActionBarItem(ref, t2); let t3; if ($[12] !== ariaLabel || $[13] !== dataOverflowingAttr || $[14] !== icon || $[15] !== props) { t3 = /*#__PURE__*/ jsx(ActionMenu.Anchor, { children: /*#__PURE__*/ jsx(IconButton, { variant: "invisible", "aria-label": ariaLabel, icon, ...props, "data-overflowing": dataOverflowingAttr, "data-component": "ActionBar.Menu.IconButton" }) }); $[12] = ariaLabel; $[13] = dataOverflowingAttr; $[14] = icon; $[15] = props; $[16] = t3; } else t3 = $[16]; let t4; if ($[17] !== returnFocusRef) { t4 = returnFocusRef && { returnFocusRef }; $[17] = returnFocusRef; $[18] = t4; } else t4 = $[18]; let t5; if ($[19] !== items) { t5 = items.map(_temp7); $[19] = items; $[20] = t5; } else t5 = $[20]; let t6; if ($[21] !== t5) { t6 = /*#__PURE__*/ jsx(ActionList, { children: t5 }); $[21] = t5; $[22] = t6; } else t6 = $[22]; let t7; if ($[23] !== t4 || $[24] !== t6) { t7 = /*#__PURE__*/ jsx(ActionMenu.Overlay, { ...t4, children: t6 }); $[23] = t4; $[24] = t6; $[25] = t7; } else t7 = $[25]; let t8; if ($[26] !== menuOpen || $[27] !== ref || $[28] !== t3 || $[29] !== t7) { t8 = /*#__PURE__*/ jsxs(ActionMenu, { anchorRef: ref, open: menuOpen, onOpenChange: setMenuOpen, children: [t3, t7] }); $[26] = menuOpen; $[27] = ref; $[28] = t3; $[29] = t7; $[30] = t8; } else t8 = $[30]; return t8; }); const VerticalDivider = () => { const $ = c(3); const ref = useRef(null); let t0; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t0 = { type: "divider" }; $[0] = t0; } else t0 = $[0]; const { dataOverflowingAttr } = useActionBarItem(ref, t0); let t1; if ($[1] !== dataOverflowingAttr) { t1 = /*#__PURE__*/ jsx("div", { ref, "data-component": "ActionBar.VerticalDivider", "aria-hidden": "true", className: ActionBar_module_css_default.Divider, "data-overflowing": dataOverflowingAttr }); $[1] = dataOverflowingAttr; $[2] = t1; } else t1 = $[2]; return t1; }; function _temp(entry) { return entry[1] !== null; } function _temp2(element) { return element.matches(FOCUSABLE_ITEM_SELECTOR); } function _temp3(item, index) { return renderMenuItem(item, index); } function _temp4(t0) { const [id, menuItem] = t0; if (menuItem.type === "divider") return /*#__PURE__*/ jsx(ActionList.Divider, {}, id); if (menuItem.type === "action") { const { onClick, icon: Icon, label, disabled } = menuItem; return /*#__PURE__*/ jsxs(ActionList.Item, { onSelect: (event) => { typeof onClick === "function" && onClick(event); }, disabled, children: [Icon ? /*#__PURE__*/ jsx(ActionList.LeadingVisual, { children: /*#__PURE__*/ jsx(Icon, {}) }) : null, label] }, id); } if (menuItem.type === "menu") { const menuItems = menuItem.items; const { icon: Icon_0, label: label_0, returnFocusRef } = menuItem; return /*#__PURE__*/ jsxs(ActionMenu, { children: [/*#__PURE__*/ jsx(ActionMenu.Anchor, { children: /*#__PURE__*/ jsxs(ActionList.Item, { children: [Icon_0 !== "none" ? /*#__PURE__*/ jsx(ActionList.LeadingVisual, { children: /*#__PURE__*/ jsx(Icon_0, {}) }) : null, label_0] }) }), /*#__PURE__*/ jsx(ActionMenu.Overlay, { ...returnFocusRef && { returnFocusRef }, children: /*#__PURE__*/ jsx(ActionList, { children: menuItems.map(_temp3) }) })] }, id); } } function _temp7(item, index) { return renderMenuItem(item, index); } //#endregion export { ActionBar, ActionBarButton, ActionBarGroup, ActionBarIconButton, ActionBarMenu, VerticalDivider };