@carbon/ibm-products
Version:
Carbon for IBM Products
166 lines (164 loc) • 5.56 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 { getDevtoolsProps } from "../../global/js/utils/devtools.js";
import { InterstitialScreenContext, blockClass } from "./context.js";
import InterstitialScreenHeader from "./InterstitialScreenHeader.js";
import InterstitialScreenBody from "./InterstitialScreenBody.js";
import InterstitialScreenFooter from "./InterstitialScreenFooter.js";
import React, { useCallback, useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { ComposedModal, unstable_FeatureFlags } from "@carbon/react";
//#region src/components/InterstitialScreen/InterstitialScreen.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.
*/
var import_classnames = /* @__PURE__ */ __toESM(require_classnames());
const componentName = "InterstitialScreen";
/**
* InterstitialScreen can be a full page or an overlay, and are
* shown on the first time a user accesses a new experience
* (e.g. upon first login or first time opening a page where a
* newly purchased capability is presented).
*/
const InterstitialScreen = React.forwardRef((props, ref) => {
const { children, className, ariaLabel = "Interstitial screen", isFullScreen = false, open = false, launcherButtonRef, onClose, ...rest } = props;
const backupRef = useRef(null);
const _forwardedRef = ref || backupRef;
const startButtonRef = useRef(void 0);
const nextButtonRef = useRef(void 0);
const [isVisibleClass, setIsVisibleClass] = useState(null);
const [progStep, setProgStep] = useState(0);
const bodyScrollRef = useRef(null);
const [stepCount, setStepCount] = useState(0);
const [disableButtonConfig, setDisableButtonConfig] = useState({
skip: false,
back: false,
next: false,
start: false
});
const variantClass = isFullScreen ? `${blockClass}--full-screen` : `${blockClass}--modal`;
const [bodyChildrenData, setBodyChildrenData] = useState(null);
const handleClose = useCallback((actionName) => {
setProgStep(0);
onClose?.(actionName ?? "close");
}, [onClose]);
useEffect(() => {
if (!open) setProgStep(0);
startButtonRef.current?.focus();
}, [
open,
progStep,
onClose
]);
useEffect(() => {
setIsVisibleClass(!isFullScreen && open ? "is-visible" : null);
nextButtonRef?.current?.focus();
if (!open && launcherButtonRef) setTimeout(() => {
launcherButtonRef.current.focus();
}, 0);
}, [
launcherButtonRef,
isFullScreen,
open
]);
useEffect(() => {
const close = (e) => {
const { key } = e;
if (key === "Escape") handleClose("close");
};
window.addEventListener("keydown", close);
return () => window.removeEventListener("keydown", close);
}, [handleClose]);
if (!open) return null;
const renderModal = () => {
return /* @__PURE__ */ React.createElement(unstable_FeatureFlags, { enableExperimentalFocusWrapWithoutSentinels: true }, /* @__PURE__ */ React.createElement(ComposedModal, {
...rest,
preventCloseOnClickOutside: true,
className: (0, import_classnames.default)(blockClass, className),
size: "lg",
onClose: handleClose,
open,
ref: _forwardedRef,
"aria-label": ariaLabel,
...getDevtoolsProps(componentName)
}, children));
};
const renderFullScreen = () => {
return /* @__PURE__ */ React.createElement("div", {
...rest,
className: (0, import_classnames.default)(blockClass, className, variantClass, isVisibleClass),
role: "main",
"aria-label": ariaLabel,
ref,
...getDevtoolsProps(componentName)
}, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}--container` }, children));
};
const handleGotoStep = (targetStep) => {
setProgStep(targetStep);
scrollBodyToTop();
};
const scrollBodyToTop = () => {
bodyScrollRef?.current?.scroll?.({ top: 0 });
};
return /* @__PURE__ */ React.createElement(InterstitialScreenContext.Provider, { value: {
bodyChildrenData,
setBodyChildrenData,
isFullScreen,
handleClose,
progStep,
setProgStep,
bodyScrollRef,
handleGotoStep,
stepCount,
setStepCount,
disableButtonConfig,
setDisableButtonConfig
} }, isFullScreen ? renderFullScreen() : renderModal());
});
InterstitialScreen.Header = InterstitialScreenHeader;
InterstitialScreen.Body = InterstitialScreenBody;
InterstitialScreen.Footer = InterstitialScreenFooter;
InterstitialScreen.displayName = componentName;
InterstitialScreen.propTypes = {
/**
* The aria label applied to the Interstitial Screen component
*/
ariaLabel: PropTypes.string,
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,
/**
* Specifies whether the component is shown as a full-screen
* experience, else it is shown as a modal by default.
*/
isFullScreen: PropTypes.bool,
/**
* Provide a ref to return focus to once the interstitial is closed.
*/
launcherButtonRef: PropTypes.any,
/**
* Function to call when the close button is clicked.
*/
onClose: PropTypes.func,
/**
* Specifies whether the component is currently open.
*/
open: PropTypes.bool
};
//#endregion
export { InterstitialScreen };