@carbon/ibm-products
Version:
Carbon for IBM Products
176 lines (174 loc) • 7.16 kB
JavaScript
/**
* 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 { useControllableState } from "../../global/js/hooks/useControllableState.js";
import { getDevtoolsProps } from "../../global/js/utils/devtools.js";
import uuidv4 from "../../global/js/utils/uuidv4.js";
import { blue90, purple70 } from "../../node_modules/@carbon/colors/es/index.js";
import { Carousel } from "../Carousel/Carousel.js";
import React, { useRef, useState } from "react";
import PropTypes from "prop-types";
import { Button, IconButton } from "@carbon/react";
import { CaretLeft, CaretRight, Close, Idea } from "@carbon/react/icons";
//#region src/components/Guidebanner/Guidebanner.tsx
/**
* Copyright IBM Corp. 2023, 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.
*/
var import_classnames = /* @__PURE__ */ __toESM(require_classnames());
const blockClass = `${pkg.prefix}--guidebanner`;
const componentName = "Guidebanner";
const defaults = {
collapsible: false,
withLeftGutter: false,
closeIconDescription: "Close",
collapseButtonLabel: "Read less",
expandButtonLabel: "Read more",
nextIconDescription: "Next",
previousIconDescription: "Back"
};
/**
* The guide banner sits at the top of a page, or page-level tab,
* to introduce foundational concepts related to the page's content.
*/
const Guidebanner = React.forwardRef((props, ref) => {
const { children, className, collapsible = defaults.collapsible, onClose, withLeftGutter = defaults.withLeftGutter, closeIconDescription = defaults.closeIconDescription, collapseButtonLabel = defaults.collapseButtonLabel, expandButtonLabel = defaults.expandButtonLabel, nextIconDescription = defaults.nextIconDescription, previousIconDescription = defaults.previousIconDescription, title, onChange, open: userOpen, ...rest } = props;
const scrollRef = useRef(null);
const toggleRef = useRef(null);
const [scrollPosition, setScrollPosition] = useState(0);
const [showNavigation, setShowNavigation] = useState(false);
const [open, setOpen] = useControllableState(userOpen ?? false, onChange);
const handleClickToggle = () => {
setOpen(!open);
};
const carouselContentId = `${uuidv4()}--carousel-content-id`;
return /* @__PURE__ */ React.createElement("div", {
...rest,
"aria-owns": open ? carouselContentId : void 0,
className: (0, import_classnames.default)(blockClass, className, collapsible && `${blockClass}__collapsible`, !open && `${blockClass}__collapsible-collapsed`, withLeftGutter && `${blockClass}__with-left-gutter`),
ref,
...getDevtoolsProps(componentName)
}, /* @__PURE__ */ React.createElement(Idea, {
size: 20,
className: `${blockClass}__icon-idea`
}), /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__title` }, title), /* @__PURE__ */ React.createElement(Carousel, {
id: carouselContentId,
className: `${blockClass}__carousel`,
fadedEdgeColor: {
left: blue90,
right: purple70
},
ref: scrollRef,
onChangeIsScrollable: (value) => {
setShowNavigation(value);
},
onScroll: (scrollPercent) => {
setScrollPosition(scrollPercent);
},
isScrollMode: true
}, children), /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)([collapsible || showNavigation ? `${blockClass}__navigation` : null]) }, collapsible && /* @__PURE__ */ React.createElement(Button, {
kind: "ghost",
size: "md",
className: `${blockClass}__toggle-button`,
onClick: handleClickToggle,
ref: toggleRef,
"aria-controls": !open ? carouselContentId : void 0,
"aria-expanded": open
}, open ? collapseButtonLabel : expandButtonLabel), showNavigation && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("span", { className: (0, import_classnames.default)(`${blockClass}__back-button`, [scrollPosition === 0 ? `${blockClass}__back-button--disabled` : null]) }, /* @__PURE__ */ React.createElement(IconButton, {
align: "top",
disabled: scrollPosition === 0,
kind: "ghost",
label: previousIconDescription,
onClick: () => {
scrollRef.current.scrollPrev();
},
size: "md"
}, /* @__PURE__ */ React.createElement(CaretLeft, { size: 16 }))), /* @__PURE__ */ React.createElement("span", { className: (0, import_classnames.default)(`${blockClass}__next-button`, [scrollPosition === 1 ? `${blockClass}__next-button--disabled` : null]) }, /* @__PURE__ */ React.createElement(IconButton, {
align: "top-right",
disabled: scrollPosition === 1,
kind: "ghost",
label: nextIconDescription,
onClick: () => {
scrollRef.current.scrollNext();
},
size: "md"
}, /* @__PURE__ */ React.createElement(CaretRight, { size: 16 }))))), onClose && /* @__PURE__ */ React.createElement("span", { className: `${blockClass}__close-button` }, /* @__PURE__ */ React.createElement(IconButton, {
align: "bottom-end",
kind: "ghost",
label: closeIconDescription,
onClick: onClose,
size: "md"
}, /* @__PURE__ */ React.createElement(Close, { size: 16 }))));
});
Guidebanner.displayName = componentName;
Guidebanner.propTypes = {
/**
* Provide the contents of the Guidebanner.
* One or more GuidebannerElement components are required.
*/
children: PropTypes.node,
/**
* Provide an optional class to be applied to the containing node.
*/
className: PropTypes.string,
/**
* Tooltip text and aria label for the Close button icon.
*/
closeIconDescription: PropTypes.string,
/**
* Text label for the Collapse button.
*/
collapseButtonLabel: PropTypes.string,
/**
* When true, the Guidebanner will initialize in a collapsed state,
* showing the title and the Expand button.
*
* When expanded, it will show the GuidebannerElement child components and the Collapse button.
*/
collapsible: PropTypes.bool,
/**
* Text label for the Expand button.
*/
expandButtonLabel: PropTypes.string,
/**
* Tooltip text and aria label for the Next button icon.
*/
nextIconDescription: PropTypes.string,
/**
* A handler for managing the controlled state of open prop. If not passed the open prop will not be honored and an uncontrolled state will be used.
*/
onChange: PropTypes.func,
/**
* If defined, a Close button will render in the top-right corner and a
* callback function will be triggered when button is clicked.
*/
onClose: PropTypes.func,
/**
* Specify whether the Guidebanner is currently open.
*/
open: PropTypes.bool,
/**
* Tooltip text and aria label for the Back button icon.
*/
previousIconDescription: PropTypes.string,
/**
* Title text.
*/
title: PropTypes.string.isRequired,
/**
* If true, insert 1 rem of "space" on the left of the component.
* This will allow the component's content to line up with other
* content on the page under special circumstances.
*/
withLeftGutter: PropTypes.bool
};
//#endregion
export { Guidebanner };