UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

1,018 lines (999 loc) • 24.9 kB
import { c } from 'react-compiler-runtime'; import React, { useEffect } from 'react'; import { useResponsiveValue, isResponsiveValue } from '../hooks/useResponsiveValue.js'; import { ArrowLeftIcon } from '@primer/octicons-react'; import { areAllValuesTheSame, haveRegularAndWideSameValue } from '../utils/getBreakpointDeclarations.js'; import { warning } from '../utils/warning.js'; import { clsx } from 'clsx'; import classes from './PageHeader.module.css.js'; import { defaultSxProp } from '../utils/defaultSxProp.js'; import { BoxWithFallback } from '../internal/components/BoxWithFallback.js'; import { jsx, Fragment, jsxs } from 'react/jsx-runtime'; import { useProvidedRefOrCreate } from '../hooks/useProvidedRefOrCreate.js'; import Heading from '../Heading/Heading.js'; import Link from '../Link/Link.js'; // Default state for the `visible` prop when a sub component is only visible on narrow viewport const hiddenOnRegularAndWide = { narrow: false, regular: true, wide: true }; // Default state for the `visible` prop when a sub component is visible on regular and wide viewport const hiddenOnNarrow = { narrow: true, regular: false, wide: false }; // Root // ----------------------------------------------------------------------------- const Root = /*#__PURE__*/React.forwardRef((t0, forwardedRef) => { const $ = c(15); const { children, className, sx: t1, as: t2, "aria-label": ariaLabel, role, hasBorder } = t0; const sx = t1 === undefined ? defaultSxProp : t1; const as = t2 === undefined ? "div" : t2; const rootRef = useProvidedRefOrCreate(forwardedRef); const isInteractive = _temp; let t3; let t4; if ($[0] !== children || $[1] !== rootRef) { t3 = function validateInteractiveElementsInTitle() { if (!(process.env.NODE_ENV !== "production")) { return; } let hasContextArea = false; let hasLeadingAction = false; if (!rootRef.current || rootRef.current.children.length <= 0) { return; } const titleArea = Array.from(rootRef.current.children).find(_temp2); if (!titleArea) { return; } for (const child_0 of React.Children.toArray(children)) { if (/*#__PURE__*/React.isValidElement(child_0) && child_0.type === ContextArea) { hasContextArea = true; } if (/*#__PURE__*/React.isValidElement(child_0) && child_0.type === LeadingAction) { hasLeadingAction = true; } } const hasInteractiveContent = Array.from(titleArea.childNodes).some(child_1 => child_1 instanceof HTMLElement && isInteractive(child_1) || Array.from(child_1.childNodes).some(child_2 => child_2 instanceof HTMLElement && isInteractive(child_2))); process.env.NODE_ENV !== "production" ? warning(hasInteractiveContent && (hasContextArea || hasLeadingAction), "When PageHeader.ContextArea or PageHeader.LeadingAction is present, we recommended not to include any interactive items in the PageHeader.TitleArea to make sure the focus order is logical.") : void 0; }; t4 = [children, rootRef]; $[0] = children; $[1] = rootRef; $[2] = t3; $[3] = t4; } else { t3 = $[2]; t4 = $[3]; } useEffect(t3, t4); let t5; if ($[4] !== className) { t5 = clsx(classes.PageHeader, className); $[4] = className; $[5] = t5; } else { t5 = $[5]; } const t6 = hasBorder ? "true" : undefined; let t7; if ($[6] !== ariaLabel || $[7] !== as || $[8] !== children || $[9] !== role || $[10] !== rootRef || $[11] !== sx || $[12] !== t5 || $[13] !== t6) { t7 = /*#__PURE__*/jsx(BoxWithFallback, { as: as, ref: rootRef, className: t5, "data-has-border": t6, sx: sx, "aria-label": ariaLabel, role: role, children: children }); $[6] = ariaLabel; $[7] = as; $[8] = children; $[9] = role; $[10] = rootRef; $[11] = sx; $[12] = t5; $[13] = t6; $[14] = t7; } else { t7 = $[14]; } return t7; }); // PageHeader.ContextArea : Only visible on narrow viewports by default to provide user context of where they are at their journey. `hidden` prop available // to manage their custom visibility but consumers should be careful if they choose to hide this on narrow viewports. // PageHeader.ContextArea Sub Components: PageHeader.ParentLink, PageHeader.ContextBar, PageHeader.ContextAreaActions // --------------------------------------------------------------------- const ContextArea = t0 => { const $ = c(9); const { children, className, hidden: t1, sx: t2 } = t0; const hidden = t1 === undefined ? hiddenOnRegularAndWide : t1; const sxProp = t2 === undefined ? defaultSxProp : t2; let t3; if ($[0] !== className) { t3 = clsx(classes.ContextArea, className); $[0] = className; $[1] = t3; } else { t3 = $[1]; } let t4; if ($[2] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== children || $[5] !== sxProp || $[6] !== t3 || $[7] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, sx: sxProp, ...t4, children: children }); $[4] = children; $[5] = sxProp; $[6] = t3; $[7] = t4; $[8] = t5; } else { t5 = $[8]; } return t5; }; // PageHeader.ParentLink : Only visible on narrow viewports by default to let users navigate up in the hierarchy. const ParentLink = /*#__PURE__*/React.forwardRef((t0, ref) => { const $ = c(16); const { children, className, sx: t1, href, "aria-label": ariaLabel, as: t2, hidden: t3 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const as = t2 === undefined ? "a" : t2; const hidden = t3 === undefined ? hiddenOnRegularAndWide : t3; let t4; if ($[0] !== className) { t4 = clsx(classes.ParentLink, className); $[0] = className; $[1] = t4; } else { t4 = $[1]; } let t5; if ($[2] !== hidden) { t5 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t5; } else { t5 = $[3]; } let t6; if ($[4] === Symbol.for("react.memo_cache_sentinel")) { t6 = /*#__PURE__*/jsx(ArrowLeftIcon, {}); $[4] = t6; } else { t6 = $[4]; } let t7; if ($[5] !== children) { t7 = /*#__PURE__*/jsx("div", { children: children }); $[5] = children; $[6] = t7; } else { t7 = $[6]; } let t8; if ($[7] !== ariaLabel || $[8] !== as || $[9] !== href || $[10] !== ref || $[11] !== sxProp || $[12] !== t4 || $[13] !== t5 || $[14] !== t7) { t8 = /*#__PURE__*/jsx(Fragment, { children: /*#__PURE__*/jsxs(Link, { ref: ref, as: as, "aria-label": ariaLabel, muted: true, className: t4, sx: sxProp, ...t5, href: href, children: [t6, t7] }) }); $[7] = ariaLabel; $[8] = as; $[9] = href; $[10] = ref; $[11] = sxProp; $[12] = t4; $[13] = t5; $[14] = t7; $[15] = t8; } else { t8 = $[15]; } return t8; }); ParentLink.displayName = 'ParentLink'; // ContextBar // Generic slot for any component above the title region. Use it for custom breadcrumbs and other navigation elements instead of ParentLink. // --------------------------------------------------------------------- const ContextBar = t0 => { const $ = c(9); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? hiddenOnRegularAndWide : t2; let t3; if ($[0] !== className) { t3 = clsx(classes.ContextBar, className); $[0] = className; $[1] = t3; } else { t3 = $[1]; } let t4; if ($[2] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== children || $[5] !== sxProp || $[6] !== t3 || $[7] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, sx: sxProp, ...t4, children: children }); $[4] = children; $[5] = sxProp; $[6] = t3; $[7] = t4; $[8] = t5; } else { t5 = $[8]; } return t5; }; // ContextAreaActions // --------------------------------------------------------------------- const ContextAreaActions = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? hiddenOnRegularAndWide : t2; let t3; if ($[0] !== className) { t3 = clsx(classes.ContextAreaActions, className); $[0] = className; $[1] = t3; } else { t3 = $[1]; } let t4; if ($[2] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== hidden) { t5 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t5; } else { t5 = $[5]; } let t6; if ($[6] !== children || $[7] !== sxProp || $[8] !== t3 || $[9] !== t4 || $[10] !== t5) { t6 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, ...t4, sx: sxProp, ...t5, children: children }); $[6] = children; $[7] = sxProp; $[8] = t3; $[9] = t4; $[10] = t5; $[11] = t6; } else { t6 = $[11]; } return t6; }; // PageHeader.TitleArea: The main title area of the page. Visible on all viewports. // PageHeader.TitleArea Sub Components: PageHeader.LeadingVisual, PageHeader.Title, PageTitle.TrailingVisual // --------------------------------------------------------------------- const TitleArea = /*#__PURE__*/React.forwardRef((t0, forwardedRef) => { const $ = c(11); const { children, className, sx: t1, hidden: t2, variant: t3 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; const variant = t3 === undefined ? "medium" : t3; const titleAreaRef = useProvidedRefOrCreate(forwardedRef); const currentVariant = useResponsiveValue(variant, "medium"); let t4; if ($[0] !== className) { t4 = clsx(classes.TitleArea, className); $[0] = className; $[1] = t4; } else { t4 = $[1]; } let t5; if ($[2] !== hidden) { t5 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t5; } else { t5 = $[3]; } let t6; if ($[4] !== children || $[5] !== currentVariant || $[6] !== sxProp || $[7] !== t4 || $[8] !== t5 || $[9] !== titleAreaRef) { t6 = /*#__PURE__*/jsx(BoxWithFallback, { className: t4, ref: titleAreaRef, "data-component": "TitleArea", "data-size-variant": currentVariant, sx: sxProp, ...t5, children: children }); $[4] = children; $[5] = currentVariant; $[6] = sxProp; $[7] = t4; $[8] = t5; $[9] = titleAreaRef; $[10] = t6; } else { t6 = $[10]; } return t6; }); TitleArea.displayName = 'TitleArea'; // PageHeader.LeadingAction and PageHeader.TrailingAction should only be visible on regular viewports. // So they come as hidden on narrow viewports by default and their visibility can be managed by their `hidden` prop. const LeadingAction = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? hiddenOnNarrow : t2; let style; if ($[0] !== sxProp) { style = {}; const { height } = sxProp; if (height) { style["--custom-height"] = height; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t3; if ($[2] !== className) { t3 = clsx(classes.LeadingAction, className); $[2] = className; $[3] = t3; } else { t3 = $[3]; } let t4; if ($[4] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t4; } else { t4 = $[5]; } let t5; if ($[6] !== children || $[7] !== style || $[8] !== sxProp || $[9] !== t3 || $[10] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_LeadingAction", sx: sxProp, style: style, ...t4, children: children }); $[6] = children; $[7] = style; $[8] = sxProp; $[9] = t3; $[10] = t4; $[11] = t5; } else { t5 = $[11]; } return t5; }; // This is reserved for only breadcrumbs. const Breadcrumbs = t0 => { const $ = c(9); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; let t3; if ($[0] !== className) { t3 = clsx(classes.Breadcrumbs, className); $[0] = className; $[1] = t3; } else { t3 = $[1]; } let t4; if ($[2] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== children || $[5] !== sxProp || $[6] !== t3 || $[7] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_Breadcrumbs", sx: sxProp, ...t4, children: children }); $[4] = children; $[5] = sxProp; $[6] = t3; $[7] = t4; $[8] = t5; } else { t5 = $[8]; } return t5; }; // PageHeader.LeadingVisual and PageHeader.TrailingVisual should remain visible on narrow viewports. const LeadingVisual = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; let style; if ($[0] !== sxProp) { style = {}; const { height } = sxProp; if (height) { style["--custom-height"] = height; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t3; if ($[2] !== className) { t3 = clsx(classes.LeadingVisual, className); $[2] = className; $[3] = t3; } else { t3 = $[3]; } let t4; if ($[4] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t4; } else { t4 = $[5]; } let t5; if ($[6] !== children || $[7] !== style || $[8] !== sxProp || $[9] !== t3 || $[10] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_LeadingVisual", sx: sxProp, style: style, ...t4, children: children }); $[6] = children; $[7] = style; $[8] = sxProp; $[9] = t3; $[10] = t4; $[11] = t5; } else { t5 = $[11]; } return t5; }; const Title = t0 => { const $ = c(14); const { children, className, sx: t1, hidden: t2, as: t3 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; const as = t3 === undefined ? "h2" : t3; let style; if ($[0] !== sxProp) { style = {}; const { fontSize, lineHeight, fontWeight } = sxProp; if (fontSize) { style["--custom-font-size"] = fontSize; } if (lineHeight) { style["--custom-line-height"] = lineHeight; } if (fontWeight) { style["--custom-font-weight"] = fontWeight; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t4; if ($[2] !== className) { t4 = clsx(classes.Title, className); $[2] = className; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== hidden) { t5 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t5; } else { t5 = $[5]; } let t6; if ($[6] !== as || $[7] !== children || $[8] !== hidden || $[9] !== style || $[10] !== sxProp || $[11] !== t4 || $[12] !== t5) { t6 = /*#__PURE__*/jsx(Heading, { className: t4, "data-component": "PH_Title", "data-hidden": hidden, as: as, style: style, sx: sxProp, ...t5, children: children }); $[6] = as; $[7] = children; $[8] = hidden; $[9] = style; $[10] = sxProp; $[11] = t4; $[12] = t5; $[13] = t6; } else { t6 = $[13]; } return t6; }; // PageHeader.LeadingVisual and PageHeader.TrailingVisual should remain visible on narrow viewports. const TrailingVisual = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; let style; if ($[0] !== sxProp) { style = {}; const { height } = sxProp; if (height) { style["--custom-height"] = height; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t3; if ($[2] !== className) { t3 = clsx(classes.TrailingVisual, className); $[2] = className; $[3] = t3; } else { t3 = $[3]; } let t4; if ($[4] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t4; } else { t4 = $[5]; } let t5; if ($[6] !== children || $[7] !== style || $[8] !== sxProp || $[9] !== t3 || $[10] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_TrailingVisual", sx: sxProp, style: style, ...t4, children: children }); $[6] = children; $[7] = style; $[8] = sxProp; $[9] = t3; $[10] = t4; $[11] = t5; } else { t5 = $[11]; } return t5; }; const TrailingAction = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? hiddenOnNarrow : t2; let style; if ($[0] !== sxProp) { style = {}; const { height } = sxProp; if (height) { style["--custom-height"] = height; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t3; if ($[2] !== className) { t3 = clsx(classes.TrailingAction, className); $[2] = className; $[3] = t3; } else { t3 = $[3]; } let t4; if ($[4] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t4; } else { t4 = $[5]; } let t5; if ($[6] !== children || $[7] !== style || $[8] !== sxProp || $[9] !== t3 || $[10] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_TrailingAction", sx: sxProp, style: style, ...t4, children: children }); $[6] = children; $[7] = style; $[8] = sxProp; $[9] = t3; $[10] = t4; $[11] = t5; } else { t5 = $[11]; } return t5; }; const Actions = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; let style; if ($[0] !== sxProp) { style = {}; const { height } = sxProp; if (height) { style["--custom-height"] = height; } $[0] = sxProp; $[1] = style; } else { style = $[1]; } let t3; if ($[2] !== className) { t3 = clsx(classes.Actions, className); $[2] = className; $[3] = t3; } else { t3 = $[3]; } let t4; if ($[4] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[4] = hidden; $[5] = t4; } else { t4 = $[5]; } let t5; if ($[6] !== children || $[7] !== style || $[8] !== sxProp || $[9] !== t3 || $[10] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, "data-component": "PH_Actions", sx: sxProp, style: style, ...t4, children: children }); $[6] = children; $[7] = style; $[8] = sxProp; $[9] = t3; $[10] = t4; $[11] = t5; } else { t5 = $[11]; } return t5; }; // PageHeader.Description: The description area of the header. Visible on all viewports const Description = t0 => { const $ = c(9); const { children, className, sx: t1, hidden: t2 } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; let t3; if ($[0] !== className) { t3 = clsx(classes.Description, className); $[0] = className; $[1] = t3; } else { t3 = $[1]; } let t4; if ($[2] !== hidden) { t4 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t4; } else { t4 = $[3]; } let t5; if ($[4] !== children || $[5] !== sxProp || $[6] !== t3 || $[7] !== t4) { t5 = /*#__PURE__*/jsx(BoxWithFallback, { className: t3, sx: sxProp, ...t4, children: children }); $[4] = children; $[5] = sxProp; $[6] = t3; $[7] = t4; $[8] = t5; } else { t5 = $[8]; } return t5; }; // PageHeader.Navigation: The local navigation area of the header. Visible on all viewports const Navigation = t0 => { const $ = c(12); const { children, className, sx: t1, hidden: t2, as, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy } = t0; const sxProp = t1 === undefined ? defaultSxProp : t1; const hidden = t2 === undefined ? false : t2; process.env.NODE_ENV !== "production" ? warning(as === "nav" && !ariaLabel && !ariaLabelledBy, "Use `aria-label` or `aria-labelledby` prop to provide an accessible label to the `nav` landmark for assistive technology") : void 0; const t3 = as === "nav" ? ariaLabel : undefined; const t4 = as === "nav" ? ariaLabelledBy : undefined; let t5; if ($[0] !== className) { t5 = clsx(classes.Navigation, className); $[0] = className; $[1] = t5; } else { t5 = $[1]; } let t6; if ($[2] !== hidden) { t6 = getHiddenDataAttributes(hidden); $[2] = hidden; $[3] = t6; } else { t6 = $[3]; } let t7; if ($[4] !== as || $[5] !== children || $[6] !== sxProp || $[7] !== t3 || $[8] !== t4 || $[9] !== t5 || $[10] !== t6) { t7 = /*#__PURE__*/jsx(BoxWithFallback, { as: as, "aria-label": t3, "aria-labelledby": t4, className: t5, "data-component": "PH_Navigation", sx: sxProp, ...t6, children: children }); $[4] = as; $[5] = children; $[6] = sxProp; $[7] = t3; $[8] = t4; $[9] = t5; $[10] = t6; $[11] = t7; } else { t7 = $[11]; } return t7; }; // Based on getBreakpointDeclarations, this function will return the // correct data attribute for the given hidden value for CSS modules. function getHiddenDataAttributes(isHidden) { if (isResponsiveValue(isHidden)) { const responsiveValue = isHidden; // Build media queries with the giving cssProperty and mapFn const narrowMediaQuery = 'narrow' in responsiveValue ? { 'data-hidden-narrow': responsiveValue.narrow || undefined } : {}; const regularMediaQuery = 'regular' in responsiveValue ? { 'data-hidden-regular': responsiveValue.regular || undefined } : {}; const wideMediaQuery = 'wide' in responsiveValue ? { 'data-hidden-wide': responsiveValue.wide || undefined } : {}; // check if all values are the same - this is not a recommended practice but we still should check for it if (areAllValuesTheSame(responsiveValue)) { // if all the values are the same, we can just use one of the value to determine the CSS property's value return { 'data-hidden-all': responsiveValue.narrow || undefined }; // check if regular and wide have the same value, if so we can just return the narrow and regular media queries } else if (haveRegularAndWideSameValue(responsiveValue)) { return { ...narrowMediaQuery, ...regularMediaQuery }; } else { return { ...narrowMediaQuery, ...regularMediaQuery, ...wideMediaQuery }; } } else { // If the given value is not a responsive value return { 'data-hidden-all': isHidden || undefined }; } } const PageHeader = Object.assign(Root, { ContextArea, ParentLink, ContextBar, TitleArea, ContextAreaActions, LeadingAction, Breadcrumbs, LeadingVisual, Title, TrailingVisual, TrailingAction, Actions, Description, Navigation }); PageHeader.displayName = 'PageHeader'; function _temp(element) { return ["a", "button"].some(selector => element.matches(selector)) || element.hasAttribute("role") && element.getAttribute("role") === "button" || element.hasAttribute("link") && element.getAttribute("role") === "link" || element.hasAttribute("tabindex"); } function _temp2(child) { return child instanceof HTMLElement && child.getAttribute("data-component") === "TitleArea"; } export { PageHeader };