@primer/react
Version:
An implementation of GitHub's Primer Design System using React
186 lines (185 loc) • 6.6 kB
JavaScript
import useIsomorphicLayoutEffect from "../../utils/useIsomorphicLayoutEffect.js";
import { useResizeObserver } from "../../hooks/useResizeObserver.js";
import { useId as useId$1 } from "../../hooks/useId.js";
import { invariant } from "../../utils/invariant.js";
import { isSlot } from "../../utils/is-slot.js";
import { createComponent } from "../../utils/create-component.js";
import { UnderlineItem, UnderlineItemList, UnderlineWrapper } from "../../internal/components/UnderlineTabbedInterface.js";
import UnderlinePanels_module_css_default from "./UnderlinePanels.module.css.js";
import { c } from "react-compiler-runtime";
import { clsx } from "clsx";
import { jsx, jsxs } from "react/jsx-runtime";
import React, { Children, cloneElement, createContext, isValidElement, useContext, useMemo, useRef, useState } from "react";
import { TabContainerElement } from "@github/tab-container-element";
//#region src/experimental/UnderlinePanels/UnderlinePanels.tsx
const TabContainerComponent = createComponent(TabContainerElement, "tab-container");
const UnderlinePanelsContext = /*#__PURE__*/ createContext({
iconsVisible: true,
loadingCounters: void 0
});
const UnderlinePanels = ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, loadingCounters, className, ...props }) => {
const [iconsVisible, setIconsVisible] = useState(true);
const wrapperRef = useRef(null);
const listRef = useRef(null);
const parentId = useId$1(props.id);
const [tabs_0, tabPanels_0, tabsHaveIcons_0] = useMemo(() => {
let tabIndex = 0;
let panelIndex = 0;
const childrenWithProps = Children.map(children, (child) => {
if (/*#__PURE__*/ isValidElement(child) && (child.type === Tab || isSlot(child, Tab))) return /*#__PURE__*/ cloneElement(child, { id: `${parentId}-tab-${tabIndex++}` });
if (/*#__PURE__*/ isValidElement(child) && (child.type === Panel || isSlot(child, Panel))) return /*#__PURE__*/ cloneElement(child, { "aria-labelledby": `${parentId}-tab-${panelIndex++}` });
return child;
});
const tabs = [];
const tabPanels = [];
for (const child_0 of Children.toArray(childrenWithProps)) {
if (!/*#__PURE__*/ isValidElement(child_0)) continue;
if (child_0.type === Tab || isSlot(child_0, Tab)) tabs.push(child_0);
else if (child_0.type === Panel || isSlot(child_0, Panel)) tabPanels.push(child_0);
}
return [
tabs,
tabPanels,
tabs.some((tab) => /*#__PURE__*/ React.isValidElement(tab) && tab.props.icon)
];
}, [children, parentId]);
const contextValue = useMemo(() => ({
iconsVisible,
loadingCounters
}), [iconsVisible, loadingCounters]);
const iconsVisibleRef = useRef(iconsVisible);
useIsomorphicLayoutEffect(() => {
iconsVisibleRef.current = iconsVisible;
}, [iconsVisible]);
const listWidthRef = useRef(0);
useResizeObserver((entries) => {
if (!tabsHaveIcons_0) return;
if (!iconsVisibleRef.current) return;
listWidthRef.current = entries[0].contentRect.width;
}, listRef, []);
useResizeObserver((resizeObserverEntries) => {
if (!tabsHaveIcons_0) return;
const wrapperWidth = resizeObserverEntries[0].contentRect.width;
setIconsVisible(wrapperWidth > listWidthRef.current);
}, wrapperRef, []);
!(tabs_0.filter((tab_0) => {
const ariaSelected = /*#__PURE__*/ React.isValidElement(tab_0) && tab_0.props["aria-selected"];
return ariaSelected === true || ariaSelected === "true";
}).length <= 1) && invariant(false, "Only one tab can be selected at a time.");
!(tabs_0.length === tabPanels_0.length) && invariant(false, `The number of tabs and panels must be equal. Counted ${tabs_0.length} tabs and ${tabPanels_0.length} panels.`);
return /*#__PURE__*/ jsx(UnderlinePanelsContext.Provider, {
value: contextValue,
children: /*#__PURE__*/ jsxs(TabContainerComponent, { children: [/*#__PURE__*/ jsx(UnderlineWrapper, {
ref: wrapperRef,
slot: "tablist-wrapper",
"data-icons-visible": iconsVisible,
className: clsx(className, UnderlinePanels_module_css_default.StyledUnderlineWrapper),
...props,
children: /*#__PURE__*/ jsx(UnderlineItemList, {
ref: listRef,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
role: "tablist",
children: tabs_0
})
}), tabPanels_0] })
});
};
UnderlinePanels.displayName = "UnderlinePanels";
const TabImpl = (t0) => {
const $ = c(15);
let ariaSelected;
let onSelect;
let props;
if ($[0] !== t0) {
({"aria-selected": ariaSelected, onSelect, ...props} = t0);
$[0] = t0;
$[1] = ariaSelected;
$[2] = onSelect;
$[3] = props;
} else {
ariaSelected = $[1];
onSelect = $[2];
props = $[3];
}
const { loadingCounters } = useContext(UnderlinePanelsContext);
let t1;
if ($[4] !== onSelect) {
t1 = (event) => {
if (!event.defaultPrevented && typeof onSelect === "function") onSelect(event);
};
$[4] = onSelect;
$[5] = t1;
} else t1 = $[5];
const clickHandler = t1;
let t2;
if ($[6] !== onSelect) {
t2 = (event_0) => {
if ((event_0.key === " " || event_0.key === "Enter") && !event_0.defaultPrevented && typeof onSelect === "function") onSelect(event_0);
};
$[6] = onSelect;
$[7] = t2;
} else t2 = $[7];
const keyDownHandler = t2;
const t3 = ariaSelected ? 0 : -1;
let t4;
if ($[8] !== ariaSelected || $[9] !== clickHandler || $[10] !== keyDownHandler || $[11] !== loadingCounters || $[12] !== props || $[13] !== t3) {
t4 = /*#__PURE__*/ jsx(UnderlineItem, {
as: "button",
role: "tab",
tabIndex: t3,
"aria-selected": ariaSelected,
type: "button",
onClick: clickHandler,
onKeyDown: keyDownHandler,
loadingCounters,
...props
});
$[8] = ariaSelected;
$[9] = clickHandler;
$[10] = keyDownHandler;
$[11] = loadingCounters;
$[12] = props;
$[13] = t3;
$[14] = t4;
} else t4 = $[14];
return t4;
};
TabImpl.displayName = "UnderlinePanels.Tab";
const Tab = /*#__PURE__*/ React.memo(TabImpl);
Tab.displayName = "UnderlinePanels.Tab";
const Panel = (t0) => {
const $ = c(6);
let children;
let rest;
if ($[0] !== t0) {
({children, ...rest} = t0);
$[0] = t0;
$[1] = children;
$[2] = rest;
} else {
children = $[1];
rest = $[2];
}
let t1;
if ($[3] !== children || $[4] !== rest) {
t1 = /*#__PURE__*/ jsx("div", {
role: "tabpanel",
...rest,
children
});
$[3] = children;
$[4] = rest;
$[5] = t1;
} else t1 = $[5];
return t1;
};
Panel.displayName = "UnderlinePanels.Panel";
var UnderlinePanels_default = Object.assign(UnderlinePanels, {
Panel,
Tab
});
Tab.__SLOT__ = Symbol("UnderlinePanels.Tab");
Panel.__SLOT__ = Symbol("UnderlinePanels.Panel");
//#endregion
export { UnderlinePanels_default as default };