UNPKG

@carbon/react

Version:

React components for the Carbon Design System

84 lines (82 loc) 3.13 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { usePrefix } from "../../internal/usePrefix.js"; import { Escape } from "../../internal/keyboard/keys.js"; import { match } from "../../internal/keyboard/match.js"; import { noopFn } from "../../internal/noopFn.js"; import { isComponentElement } from "../../internal/utils.js"; import { useMergedRefs } from "../../internal/useMergedRefs.js"; import { useWindowEvent } from "../../internal/useEvent.js"; import Switcher from "./Switcher.js"; import classNames from "classnames"; import React, { useRef, useState } from "react"; import PropTypes from "prop-types"; import { jsx } from "react/jsx-runtime"; //#region src/components/UIShell/HeaderPanel.tsx /** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ const HeaderPanel = React.forwardRef(({ children, className: customClassName, expanded, addFocusListeners = true, onHeaderPanelFocus = noopFn, href, ...rest }, ref) => { const prefix = usePrefix(); const headerPanelReference = useRef(null); const headerPanelRef = useMergedRefs([headerPanelReference, ref]); const controlled = useRef(expanded !== void 0).current; const [expandedState, setExpandedState] = useState(expanded); const expandedProp = controlled ? expanded : expandedState; const [lastClickedElement, setLastClickedElement] = useState(null); const className = classNames(`${prefix}--header-panel`, { [`${prefix}--header-panel--expanded`]: expandedProp, [customClassName]: !!customClassName }); const eventHandlers = {}; if (addFocusListeners) { eventHandlers.onBlur = (event) => { if (!event.currentTarget.contains(event.relatedTarget) && !lastClickedElement?.classList?.contains(`${prefix}--switcher__item-link`)) { setExpandedState(false); setLastClickedElement(null); if (expanded) onHeaderPanelFocus(); } }; eventHandlers.onKeyDown = (event) => { if (match(event, Escape)) { setExpandedState(false); onHeaderPanelFocus(); if (href) window.location.href = href; } }; } useWindowEvent("click", (event) => { const { target } = event; if (!(target instanceof Element)) return; setLastClickedElement(target); if (isComponentElement(children, Switcher) && !target.closest(`.${prefix}--header-panel--expanded`) && !target.closest(`.${prefix}--header__action`) && !headerPanelReference?.current?.classList.contains(`${prefix}--switcher`) && expanded) { setExpandedState(false); onHeaderPanelFocus(); } }); return /* @__PURE__ */ jsx("div", { ...rest, className, ref: headerPanelRef, ...eventHandlers, children }); }); HeaderPanel.propTypes = { addFocusListeners: PropTypes.bool, children: PropTypes.node, className: PropTypes.string, expanded: PropTypes.bool, href: PropTypes.string, onHeaderPanelFocus: PropTypes.func }; HeaderPanel.displayName = "HeaderPanel"; //#endregion export { HeaderPanel as default };