@carbon/ibm-products
Version:
Carbon for IBM Products
111 lines (109 loc) • 4.62 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 { getDevtoolsProps } from "../../global/js/utils/devtools.js";
import { InterstitialScreenContext, blockClass } from "./context.js";
import React, { isValidElement, useContext, useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { ModalBody } from "@carbon/react";
import { initCarousel } from "@carbon/utilities";
//#region src/components/InterstitialScreen/InterstitialScreenBody.tsx
/**
* Copyright IBM Corp. 2024, 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.
*/
const InterstitialScreenBody = React.forwardRef((props, ref) => {
const { className = "", contentRenderer, ...rest } = props;
const bodyBlockClass = `${blockClass}--internal-body`;
const [stepType, setStepType] = useState();
const { setBodyChildrenData, bodyChildrenData, isFullScreen, setProgStep, bodyScrollRef, handleGotoStep, progStep, setStepCount, disableButtonConfig, setDisableButtonConfig } = useContext(InterstitialScreenContext);
const carouselContainerRef = useRef(null);
const carouselInitRef = useRef(null);
useEffect(() => {
const _bodyContent = contentRenderer?.({
handleGotoStep,
progStep,
disableActionButton
}) ?? props.children;
const children = isValidElement(_bodyContent) && _bodyContent.props.children != null ? _bodyContent.props.children : _bodyContent;
const validChildren = React.Children.toArray(children).filter(isValidElement);
if (validChildren.length > 1) {
setStepType("multi");
setStepCount?.(validChildren.length);
setBodyChildrenData?.(validChildren);
} else {
setStepType("single");
setStepCount?.(1);
setBodyChildrenData?.(_bodyContent);
}
}, [props.children, contentRenderer]);
useEffect(() => {
if (stepType !== "multi" || !carouselContainerRef.current || !bodyChildrenData) return;
carouselInitRef.current?.destroyEvents?.();
carouselInitRef.current = initCarousel(carouselContainerRef.current, {
onViewChangeStart: () => {},
onViewChangeEnd: ({ currentIndex }) => {
setProgStep?.(currentIndex);
},
excludeSwipeSupport: true,
useMaxHeight: true
});
return () => {
carouselInitRef.current?.destroyEvents?.();
carouselInitRef.current = null;
};
}, [stepType]);
useEffect(() => {
if (stepType === "multi" && typeof progStep === "number") {
const activeIndex = (carouselInitRef.current?.getActiveItem?.())?.index ?? -1;
if (activeIndex !== -1 && activeIndex < progStep) carouselInitRef.current?.next?.();
else if (activeIndex !== -1 && activeIndex > progStep) carouselInitRef.current?.prev?.();
}
}, [progStep, stepType]);
const disableActionButton = (config) => {
setDisableButtonConfig?.({
...disableButtonConfig,
...config
});
};
const renderBody = () => /* @__PURE__ */ React.createElement("div", {
className: `${blockClass}--body ${className}`,
ref: isFullScreen ? bodyScrollRef ?? ref : ref,
...getDevtoolsProps("InterstitialScreenBody"),
...isFullScreen ? rest : {}
}, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}--content` }, stepType === "multi" ? /* @__PURE__ */ React.createElement("div", {
className: `${blockClass}__carousel `,
ref: (node) => {
carouselContainerRef.current = node;
}
}, React.Children.map(bodyChildrenData, (child, index) => isValidElement(child) ? /* @__PURE__ */ React.createElement("div", { "data-index": index }, child) : null)) : stepType === "single" ? bodyChildrenData : ""));
return isFullScreen ? renderBody() : /* @__PURE__ */ React.createElement(ModalBody, {
ref: bodyScrollRef ?? ref,
className: bodyBlockClass,
...rest
}, renderBody());
});
InterstitialScreenBody.propTypes = {
/**
* Optional static content for body
*/
children: PropTypes.node,
/**
* Provide an optional class to be applied to the containing node.
*/
className: PropTypes.string,
/**
*You can provide content either through a callback (contentRenderer) or as static children—but not both.
* If both are provided, contentRenderer always takes precedence. This optional callback should return the content
* to be rendered in the body section, which can be either a single element or an array of elements based on your needs.
* If internal state access isn’t required, you can simply use static children instead
*/
contentRenderer: PropTypes.func
};
//#endregion
export { InterstitialScreenBody as default };