UNPKG

@carbon/ibm-products

Version:

Carbon for IBM Products

201 lines (192 loc) 6.81 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. */ 'use strict'; var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js'); var react = require('@carbon/react'); var React = require('react'); var index = require('../../_virtual/index.js'); var cx = require('classnames'); var devtools = require('../../global/js/utils/devtools.js'); var settings = require('../../settings.js'); var InterstitialScreenHeader = require('./InterstitialScreenHeader.js'); var InterstitialScreenBody = require('./InterstitialScreenBody.js'); var InterstitialScreenFooter = require('./InterstitialScreenFooter.js'); var context = require('./context.js'); const componentName = 'InterstitialScreen'; // Define the type for InterstitialScreen, extending it to include Header /** * 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). */ exports.InterstitialScreen = /*#__PURE__*/React.forwardRef((props, ref) => { const { children, className, ariaLabel = 'Interstitial screen', isFullScreen = false, open = false, launcherButtonRef, onClose, ...rest } = props; const backupRef = React.useRef(null); const _forwardedRef = ref || backupRef; const scrollRef = React.useRef(undefined); const startButtonRef = React.useRef(undefined); const nextButtonRef = React.useRef(undefined); const [isVisibleClass, setIsVisibleClass] = React.useState(null); const [progStep, setProgStep] = React.useState(0); const bodyScrollRef = React.useRef(null); const [stepCount, setStepCount] = React.useState(0); const [disableButtonConfig, setDisableButtonConfig] = React.useState({ skip: false, back: false, next: false, start: false }); const variantClass = isFullScreen ? `${context.blockClass}--full-screen` : `${context.blockClass}--modal`; const [bodyChildrenData, setBodyChildrenData] = React.useState(null); const handleClose = React.useCallback(actionName => { setProgStep(0); onClose?.(actionName ?? 'close'); }, [onClose]); React.useEffect(() => { if (!open) { setProgStep(0); } startButtonRef.current?.focus(); }, [open, progStep, onClose]); React.useEffect(() => { // for modal only, "is-visible" triggers animation setIsVisibleClass(!isFullScreen && open ? 'is-visible' : null); nextButtonRef?.current?.focus(); if (!open && launcherButtonRef) { setTimeout(() => { launcherButtonRef.current.focus(); }, 0); } }, [launcherButtonRef, isFullScreen, open]); // hitting escape key also closes this component React.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(react.unstable_FeatureFlags, { enableExperimentalFocusWrapWithoutSentinels: true }, /*#__PURE__*/React.createElement(react.ComposedModal, _rollupPluginBabelHelpers.extends({}, rest, { preventCloseOnClickOutside: true, className: cx(context.blockClass, // Apply the block class to the main HTML element className // Apply any supplied class names to the main HTML element. ), size: "lg", onClose: handleClose, open: open, ref: _forwardedRef, "aria-label": ariaLabel }, devtools.getDevtoolsProps(componentName)), children)); }; const renderFullScreen = () => { return /*#__PURE__*/React.createElement("div", _rollupPluginBabelHelpers.extends({}, rest, { className: cx(context.blockClass, // Apply the block class to the main HTML element className, // Apply any supplied class names to the main HTML element. variantClass, isVisibleClass), role: "main", "aria-label": ariaLabel, ref: ref }, devtools.getDevtoolsProps(componentName)), /*#__PURE__*/React.createElement("div", { className: `${context.blockClass}--container` }, children)); }; const handleGotoStep = targetStep => { setProgStep(targetStep); scrollRef.current.scrollToView(targetStep); scrollBodyToTop(); }; const scrollBodyToTop = () => { bodyScrollRef.current?.scroll?.({ top: 0, behavior: 'smooth' }); }; return /*#__PURE__*/React.createElement(context.InterstitialScreenContext.Provider, { value: { bodyChildrenData, setBodyChildrenData, isFullScreen, handleClose, progStep, setProgStep, bodyScrollRef, scrollRef, handleGotoStep, stepCount, setStepCount, disableButtonConfig, setDisableButtonConfig } }, isFullScreen ? renderFullScreen() : renderModal()); }); exports.InterstitialScreen.Header = InterstitialScreenHeader.default; exports.InterstitialScreen.Body = InterstitialScreenBody.default; exports.InterstitialScreen.Footer = InterstitialScreenFooter.default; // Return a placeholder if not released and not enabled by feature flag exports.InterstitialScreen = settings.pkg.checkComponentEnabled(exports.InterstitialScreen, componentName); // The display name of the component, used by React. Note that displayName // is used in preference to relying on function.name. exports.InterstitialScreen.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. exports.InterstitialScreen.propTypes = { /** * The aria label applied to the Interstitial Screen component */ ariaLabel: index.default.string, children: index.default.node, /** * Provide an optional class to be applied to the containing node. */ className: index.default.string, /** * Tooltip text and aria label for the Close button icon. */ closeIconDescription: index.default.string, /** * Specifies whether the component is shown as a full-screen * experience, else it is shown as a modal by default. */ isFullScreen: index.default.bool, /** * Provide a ref to return focus to once the interstitial is closed. */ launcherButtonRef: index.default.any, /** * Function to call when the close button is clicked. */ onClose: index.default.func, /** * Specifies whether the component is currently open. */ open: index.default.bool };