UNPKG

@carbon/ibm-products

Version:
159 lines (157 loc) 6.12 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. */ import { __toESM } from "../../_virtual/_rolldown/runtime.js"; import { require_classnames } from "../../node_modules/classnames/index.js"; import { pkg } from "../../settings.js"; import { usePrefersReducedMotion } from "../../global/js/hooks/usePrefersReducedMotion.js"; import { getDevtoolsProps } from "../../global/js/utils/devtools.js"; import { useWebTerminal } from "./hooks/index.js"; import React, { useEffect, useMemo, useRef, useState } from "react"; import PropTypes from "prop-types"; import { Button, OverflowMenu, OverflowMenuItem, Theme } from "@carbon/react"; import { Close, Help } from "@carbon/react/icons"; //#region src/components/WebTerminal/WebTerminal.tsx /** * Copyright IBM Corp. 2020, 2022 * * 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__ */ __toESM(require_classnames()); const componentName = "WebTerminal"; const blockClass = `${pkg.prefix}--web-terminal`; const defaults = { actions: Object.freeze([]), documentationLinks: Object.freeze([]), documentationLinksIconDescription: "Show documentation links", isInitiallyOpen: false, webTerminalAriaLabel: "Web terminal header" }; /** * The `WebTerminal` is prompted by the user and is persistent until dismissed. The purpose of a web terminal is to provide users with the ability to type commands manually instead of using the GUI. */ const WebTerminal = React.forwardRef(({ actions = defaults.actions, children, className, closeIconDescription, documentationLinks = defaults.documentationLinks, documentationLinksIconDescription = defaults.documentationLinksIconDescription, isInitiallyOpen = defaults.isInitiallyOpen, webTerminalAriaLabel = defaults.webTerminalAriaLabel, ...rest }, ref) => { const localRef = useRef(null); const webTerminalRef = ref ?? localRef; const { open, closeWebTerminal, openWebTerminal } = useWebTerminal(); const [shouldRender, setRender] = useState(open); const shouldReduceMotion = usePrefersReducedMotion(); const showDocumentationLinks = useMemo(() => documentationLinks.length > 0, [documentationLinks]); useEffect(() => { if (open) setRender(true); }, [open]); /** On render, check if user want's the web terminal to be open by default */ useEffect(() => { if (isInitiallyOpen) openWebTerminal?.(); }, []); /** When the web terminal slide in animation is complete, sets render to false. */ const onAnimationEnd = () => { if (!open) setRender(false); }; const handleCloseTerminal = () => { /** If the user prefers reduced motion, we have to manually set render to false because onAnimationEnd will never be called. */ if (shouldReduceMotion) setRender(false); closeWebTerminal?.(); }; return shouldRender ? /* @__PURE__ */ React.createElement("div", { ...rest, ...getDevtoolsProps(componentName), ref: webTerminalRef, className: (0, import_classnames.default)([ blockClass, className, { [`${blockClass}--open`]: open, [`${blockClass}--closed`]: !open } ]), onAnimationEnd }, /* @__PURE__ */ React.createElement("header", { "aria-label": webTerminalAriaLabel, className: `${blockClass}__bar` }, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__actions` }, showDocumentationLinks && /* @__PURE__ */ React.createElement(OverflowMenu, { renderIcon: (props) => /* @__PURE__ */ React.createElement(Help, { size: 16, ...props }), iconDescription: documentationLinksIconDescription, "aria-label": documentationLinksIconDescription, menuOptionsClass: `${blockClass}__documentation-overflow`, size: "lg" }, documentationLinks.map(({ ...rest }, i) => /* @__PURE__ */ React.createElement(OverflowMenuItem, { key: i, ...rest }))), actions.map(({ renderIcon, onClick, iconDescription }) => /* @__PURE__ */ React.createElement(Button, { key: iconDescription, hasIconOnly: true, renderIcon, onClick, iconDescription, kind: "ghost", "aria-label": iconDescription }))), /* @__PURE__ */ React.createElement(Button, { hasIconOnly: true, renderIcon: (props) => /* @__PURE__ */ React.createElement(Close, { size: 16, ...props }), kind: "ghost", iconDescription: closeIconDescription, onClick: handleCloseTerminal, onAnimationEnd: (event) => event.stopPropagation() })), /* @__PURE__ */ React.createElement(Theme, { theme: "g100" }, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__body` }, children))) : null; }); WebTerminal.displayName = componentName; WebTerminal.propTypes = { /** * An array of actions to be displayed in the web terminal header bar */ /**@ts-ignore */ actions: PropTypes.arrayOf(PropTypes.shape({ renderIcon: PropTypes.func.isRequired, onClick: PropTypes.func.isRequired, iconDescription: PropTypes.string.isRequired })), /** * Provide your own terminal component as children to show up in the web terminal */ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired, /** * Custom classname for additional styling of the web terminal */ className: PropTypes.string, /** * Icon description for the close button */ closeIconDescription: PropTypes.string.isRequired, /** * Array of objects for each documentation link. Each documentation link uses the prop types of OverflowMenuItems. See more: https://react.carbondesignsystem.com/?path=/docs/components-overflowmenu--default */ /**@ts-ignore */ documentationLinks: PropTypes.arrayOf(PropTypes.shape({ ...OverflowMenuItem.propTypes })), /** * Description for the documentation link overflow menu tooltip */ documentationLinksIconDescription: PropTypes.string, /** * Optionally pass if the web terminal should be open by default */ isInitiallyOpen: PropTypes.bool, /** * Specifies aria label for Web terminal */ webTerminalAriaLabel: PropTypes.string }; //#endregion export { WebTerminal };