UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

204 lines (193 loc) 7.06 kB
/** * Copyright IBM Corp. 2020, 2025 * * 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 { extends as _extends } from '../../_virtual/_rollupPluginBabelHelpers.js'; import { OverflowMenuItem, OverflowMenu, Button, Theme } from '@carbon/react'; import { Help, Close } from '@carbon/react/icons'; import React__default, { useRef, useState, useMemo, useEffect } from 'react'; import PropTypes from '../../_virtual/index.js'; import cx from 'classnames'; import { getDevtoolsProps } from '../../global/js/utils/devtools.js'; import { pkg } from '../../settings.js'; import { useWebTerminal } from './hooks/index.js'; import { usePrefersReducedMotion } from '../../global/js/hooks/usePrefersReducedMotion.js'; // The block part of our conventional BEM class names (blockClass__E--M). const componentName = 'WebTerminal'; const blockClass = `${pkg.prefix}--web-terminal`; // Default values for props 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. */ let WebTerminal = /*#__PURE__*/React__default.forwardRef((_ref, ref) => { let { // The component props, in alphabetical order (for consistency). actions = defaults.actions, children, className, closeIconDescription, documentationLinks = defaults.documentationLinks, documentationLinksIconDescription = defaults.documentationLinksIconDescription, isInitiallyOpen = defaults.isInitiallyOpen, webTerminalAriaLabel = defaults.webTerminalAriaLabel, // Collect any other property values passed in. ...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?.(); } }, []); // eslint-disable-line /** 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__default.createElement("div", _extends({}, rest, getDevtoolsProps(componentName), { ref: webTerminalRef, className: cx([blockClass, className, { [`${blockClass}--open`]: open, [`${blockClass}--closed`]: !open }]), onAnimationEnd: onAnimationEnd }), /*#__PURE__*/React__default.createElement("header", { "aria-label": webTerminalAriaLabel, className: `${blockClass}__bar` }, /*#__PURE__*/React__default.createElement("div", { className: `${blockClass}__actions` }, showDocumentationLinks && /*#__PURE__*/React__default.createElement(OverflowMenu, { renderIcon: props => /*#__PURE__*/React__default.createElement(Help, _extends({ size: 16 }, props)), iconDescription: documentationLinksIconDescription, "aria-label": documentationLinksIconDescription, menuOptionsClass: `${blockClass}__documentation-overflow`, size: "lg" }, documentationLinks.map((_ref2, i) => { let { ...rest } = _ref2; return /*#__PURE__*/React__default.createElement(OverflowMenuItem, _extends({ key: i }, rest)); })), actions.map(_ref3 => { let { renderIcon, onClick, iconDescription } = _ref3; return /*#__PURE__*/React__default.createElement(Button, { key: iconDescription, hasIconOnly: true, renderIcon: renderIcon, onClick: onClick, iconDescription: iconDescription, kind: "ghost", "aria-label": iconDescription }); })), /*#__PURE__*/React__default.createElement(Button, { hasIconOnly: true, renderIcon: props => /*#__PURE__*/React__default.createElement(Close, _extends({ size: 16 }, props)), kind: "ghost", iconDescription: closeIconDescription, onClick: handleCloseTerminal, onAnimationEnd: event => event.stopPropagation() })), /*#__PURE__*/React__default.createElement(Theme, { theme: "g100" }, /*#__PURE__*/React__default.createElement("div", { className: `${blockClass}__body` }, children))) : null; }); // Return a placeholder if not released and not enabled by feature flag WebTerminal = pkg.checkComponentEnabled(WebTerminal, componentName); // The display name of the component, used by React. Note that displayName // is used in preference to relying on function.name. WebTerminal.displayName = componentName; // The types and DocGen commentary for the component props, // in alphabetical order (for consistency). // See https://www.npmjs.com/package/prop-types#usage. 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 }; export { WebTerminal };