UNPKG

@carbon/ibm-products

Version:
166 lines (164 loc) 6.66 kB
/** * 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 pconsole_default from "../../global/js/utils/pconsole.js"; import { pkg } from "../../settings.js"; import { getDevtoolsProps } from "../../global/js/utils/devtools.js"; import { clamp } from "../../global/js/utils/clamp.js"; import { useCoachmark } from "../Coachmark/utils/context.js"; import { Carousel } from "../Carousel/Carousel.js"; import React, { Children, useEffect, useMemo, useRef, useState } from "react"; import PropTypes from "prop-types"; import { Button } from "@carbon/react"; //#region src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.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}--coachmark-overlay-elements`; const componentName = "CoachmarkOverlayElements"; const defaults = { isVisible: false, nextButtonText: "Next", previousButtonLabel: "Back", closeButtonLabel: "Got it", onNext: void 0, onBack: void 0, currentStep: 0 }; /** * Composable container to allow for the displaying of CoachmarkOverlayElement * components in a carousel fashion. * @deprecated This component is deprecated. */ const CoachmarkOverlayElements = React.forwardRef(({ className, children, isVisible = defaults.isVisible, renderMedia, currentStep = defaults.currentStep, nextButtonText = defaults.nextButtonText, previousButtonLabel = defaults.previousButtonLabel, closeButtonLabel = defaults.closeButtonLabel, onNext = defaults.onNext, onBack = defaults.onBack, ...rest }, ref) => { const buttonFocusRef = useRef(void 0); const scrollRef = useRef(void 0); const [scrollPosition, setScrollPosition] = useState(0); const [currentProgStep, _setCurrentProgStep] = useState(currentStep); const coachmark = useCoachmark(); const setCurrentProgStep = (value) => { if (currentProgStep > 0 && value === 0 && buttonFocusRef.current) setTimeout(() => { buttonFocusRef.current?.focus(); }, 1e3); _setCurrentProgStep(value); }; const numProgSteps = Children.count(children); const progStepFloor = 0; const progStepCeil = numProgSteps - 1; const renderMediaContent = useMemo(() => renderMedia?.({ playStep: currentProgStep }), [currentProgStep, renderMedia]); useEffect(() => { const targetStep = clamp(currentStep, progStepFloor, progStepCeil); scrollRef?.current?.scrollToView?.(targetStep); }, [currentStep]); useEffect(() => { if (buttonFocusRef.current) buttonFocusRef.current.focus(); }, []); useEffect(() => { setTimeout(() => { if (buttonFocusRef.current && isVisible) buttonFocusRef.current.focus(); }, 100); }, [isVisible]); if (!coachmark) return pconsole_default.warn(`The ${componentName} is a composable container element which should be used only within the scope of a Coachmark or a CoachmarkFixed component.`); return /* @__PURE__ */ React.createElement("section", { ...rest, className: (0, import_classnames.default)(blockClass, className, {}), ref, ...getDevtoolsProps(componentName) }, renderMedia && /* @__PURE__ */ React.createElement("div", { className: `${blockClass}__element-stepped-media` }, renderMediaContent), numProgSteps === 1 ? /* @__PURE__ */ React.createElement(React.Fragment, null, children, closeButtonLabel && /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)(`${blockClass}__footer`, "coachmark-carousel-controls") }, /* @__PURE__ */ React.createElement(Button, { size: "sm", ...coachmark.closeButtonProps, ref: buttonFocusRef }, closeButtonLabel))) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Carousel, { ref: scrollRef, onScroll: (scrollPercent) => { setScrollPosition(scrollPercent); } }, children), /* @__PURE__ */ React.createElement("div", { className: (0, import_classnames.default)(`${blockClass}__footer`) }, /* @__PURE__ */ React.createElement("div", { className: `${blockClass}--controls-progress` }, `${currentProgStep + 1} / ${numProgSteps}`), scrollPosition > 0 && /* @__PURE__ */ React.createElement(Button, { size: "sm", kind: "ghost", title: previousButtonLabel, disabled: scrollPosition === 0, onClick: () => { const targetStep = clamp(currentProgStep - 1, progStepFloor, progStepCeil); scrollRef?.current?.scrollToView?.(targetStep); setCurrentProgStep(targetStep); onBack?.(); } }, previousButtonLabel), currentProgStep < progStepCeil ? /* @__PURE__ */ React.createElement(Button, { size: "sm", ref: buttonFocusRef, title: nextButtonText, disabled: scrollPosition === 1, onClick: () => { const targetStep = clamp(currentProgStep + 1, progStepFloor, progStepCeil); scrollRef?.current?.scrollToView?.(targetStep); setCurrentProgStep(targetStep); onNext?.(); } }, nextButtonText) : closeButtonLabel && /* @__PURE__ */ React.createElement(Button, { size: "sm", ref: buttonFocusRef, ...coachmark.closeButtonProps }, closeButtonLabel)))); }); /**@ts-ignore*/ CoachmarkOverlayElements.deprecated = { level: "warn", details: `${componentName} is deprecated.` }; CoachmarkOverlayElements.displayName = componentName; CoachmarkOverlayElements.propTypes = { /** * CoachmarkOverlayElements should be used with one or many CoachmarkOverlayElement components as children. * @see CoachmarkOverlayElement */ children: PropTypes.node.isRequired, /** * Optional class name for this component. */ className: PropTypes.string, /** * The label for the Close button. */ closeButtonLabel: PropTypes.string, /** * Current step of the coachmarks */ currentStep: PropTypes.number, /** * The visibility of CoachmarkOverlayElements is * managed in the parent component. */ isVisible: PropTypes.bool, /** * The label for the Next button. */ nextButtonText: PropTypes.string, /** * Optional callback called when clicking on the Previous button. */ onBack: PropTypes.func, /** * Optional callback called when clicking on the Next button. */ onNext: PropTypes.func, /** * The label for the Previous button. */ previousButtonLabel: PropTypes.string, /** * Optional prop to render any media like images or animated media. */ renderMedia: PropTypes.func }; //#endregion export { CoachmarkOverlayElements };