UNPKG

@carbon/ibm-products

Version:
163 lines (161 loc) 7.35 kB
/** * Copyright IBM Corp. 2020, 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 require_runtime = require("../../_virtual/_rolldown/runtime.js"); const require_index = require("../../node_modules/classnames/index.js"); const require_pconsole = require("../../global/js/utils/pconsole.js"); const require_settings = require("../../settings.js"); const require_useIsomorphicEffect = require("../../global/js/hooks/useIsomorphicEffect.js"); const require_devtools = require("../../global/js/utils/devtools.js"); const require_CoachmarkHeader = require("../Coachmark/CoachmarkHeader.js"); let react = require("react"); react = require_runtime.__toESM(react); let prop_types = require("prop-types"); prop_types = require_runtime.__toESM(prop_types); let _carbon_react = require("@carbon/react"); let react_dom = require("react-dom"); let _carbon_react_icons = require("@carbon/react/icons"); //#region src/components/CoachmarkStack/CoachmarkStackHome.tsx /** * Copyright IBM Corp. 2023, 2024 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ var import_classnames = /* @__PURE__ */ require_runtime.__toESM(require_index.default); const blockClass = `${require_settings.pkg.prefix}--coachmark-stacked-home`; const overlayClass = `${require_settings.pkg.prefix}--coachmark-overlay`; const componentName = "CoachmarkStackHome"; /** * DO NOT USE. This component is for the exclusive use * of other Onboarding components. */ const CoachmarkStackHome = (0, react.forwardRef)(({ className, description, isOpen, renderMedia, navLinkLabels, onClickNavItem, onClose, portalTarget, closeButtonLabel, title, tooltipAlign, ...rest }, ref) => { const buttonFocusRef = (0, react.useRef)(null); const [linkFocusIndex, setLinkFocusIndex] = (0, react.useState)(0); const navItemRefs = (0, react.useRef)([]); const [overflowStates, setOverflowStates] = (0, react.useState)([]); (0, react.useEffect)(() => { setTimeout(() => { if (isOpen && buttonFocusRef.current) buttonFocusRef.current.focus(); }, 100); }, [isOpen]); const portalNode = (0, react.useRef)(null); require_useIsomorphicEffect.useIsomorphicEffect(() => { portalNode.current = portalTarget ? document?.querySelector(portalTarget) ?? document?.querySelector("body") : document?.querySelector("body"); }, [portalTarget]); if (!navLinkLabels) return require_pconsole.default.warn(`${componentName} is an Onboarding internal component and is not intended for general use.`); const itemRefHandler = (index, node) => { if (node && navItemRefs.current[index] !== node) { const isOverflowing = node.scrollWidth > node.clientWidth; navItemRefs.current[index] = node; setOverflowStates((prev) => { const newState = [...prev]; newState[index] = isOverflowing; return newState; }); } }; function renderNavLink(index, label, ref = null) { const isOverflowing = overflowStates[index] ?? false; return /* @__PURE__ */ react.default.createElement("li", { key: index, ref: (node) => { itemRefHandler(index, node); } }, /* @__PURE__ */ react.default.createElement(_carbon_react.Button, { kind: "ghost", size: "sm", onClick: () => { setLinkFocusIndex(index); onClickNavItem(index + 1); }, ref }, isOverflowing ? /* @__PURE__ */ react.default.createElement(_carbon_react.Tooltip, { highContrast: false, label, align: tooltipAlign, className: `${blockClass}__navLinkLabels-tooltip` }, /* @__PURE__ */ react.default.createElement("span", { className: `${blockClass}__navLinkLabels-text` }, label)) : label)); } return portalNode?.current ? (0, react_dom.createPortal)(/* @__PURE__ */ react.default.createElement("div", { ...rest, className: (0, import_classnames.default)(blockClass, className), ref, ...require_devtools.getDevtoolsProps(componentName) }, /* @__PURE__ */ react.default.createElement(require_CoachmarkHeader.CoachmarkHeader, { onClose: () => { setLinkFocusIndex(0); onClose(); } }), /* @__PURE__ */ react.default.createElement("div", { className: `${overlayClass}__body` }, /* @__PURE__ */ react.default.createElement("div", { className: `${overlayClass}-element` }, !renderMedia && /* @__PURE__ */ react.default.createElement(_carbon_react_icons.Idea, { size: 20, className: `${blockClass}__icon-idea` }), renderMedia && /* @__PURE__ */ react.default.createElement("div", { className: `${blockClass}__element-stepped-media` }, renderMedia({ playStep: 0 })), /* @__PURE__ */ react.default.createElement("div", { className: `${overlayClass}-element__content` }, title && /* @__PURE__ */ react.default.createElement("h2", { className: `${overlayClass}-element__title` }, title), description && /* @__PURE__ */ react.default.createElement("p", { className: `${overlayClass}-element__body` }, description)), /* @__PURE__ */ react.default.createElement("ul", { className: `${blockClass}__nav-links` }, navLinkLabels.map((label, index) => { if (index === linkFocusIndex) return renderNavLink(index, label, buttonFocusRef); return renderNavLink(index, label); })), closeButtonLabel && /* @__PURE__ */ react.default.createElement("div", { className: `${overlayClass}__footer` }, /* @__PURE__ */ react.default.createElement(_carbon_react.Button, { size: "sm", onClick: () => { setLinkFocusIndex(0); onClose(); } }, closeButtonLabel))))), portalNode?.current) : null; }); CoachmarkStackHome.displayName = componentName; CoachmarkStackHome.propTypes = { /** * Optional class name for this component. */ className: prop_types.default.string, /** * The label for the button that will close the stack */ closeButtonLabel: prop_types.default.string, /** * The description of the Coachmark. */ description: prop_types.default.node.isRequired, /** * If the stack home is open. */ isOpen: prop_types.default.bool.isRequired, /** * The labels used to link to the stackable Coachmarks. */ navLinkLabels: prop_types.default.arrayOf(prop_types.default.string.isRequired).isRequired, /** * For internal use only by CoachmarkStack and CoachmarkStackHome. */ onClickNavItem: prop_types.default.func.isRequired, /** * Function to call when the stack closes. */ onClose: prop_types.default.func.isRequired, /** * By default, the CoachmarkStackHome will be appended to the end of `document.body`. * The CoachmarkStackHome will remain persistent as the user navigates the app until * the user closes the CoachmarkStackHome. * * Alternatively, the app developer can tightly couple the CoachmarkStackHome to a DOM * element or other component by specifying a CSS selector. The CoachmarkStackHome will * remain visible as long as that element remains visible or mounted. When the * element is hidden or component is unmounted, the CoachmarkStackHome will disappear. */ portalTarget: prop_types.default.string, /** * Optional prop to render any media like images or animated media. */ renderMedia: prop_types.default.func, /** * The title of the Coachmark. */ title: prop_types.default.string.isRequired, /** * Label's tooltip position */ tooltipAlign: prop_types.default.oneOf(["top", "bottom"]) }; //#endregion exports.CoachmarkStackHome = CoachmarkStackHome;