diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index ca430ab0d1..51aa7c1f42 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -182,28 +182,6 @@ jobs:
name: playwright-avt-report
path: .playwright
- vrt-runner:
- runs-on: ubuntu-latest
- steps:
- - name: Checkout
- uses: actions/checkout@v2
- - name: Setup Node.js
- uses: actions/setup-node@v2
- with:
- node-version: '20.x'
- cache: yarn
- - name: Install
- run: yarn
- - name: Install browsers
- run: yarn playwright install --with-deps
- - name: Build project
- run: yarn build
- - name: Run VRT
- working-directory: packages/core
- env:
- PERCY_TOKEN: web_d04495b0b413d61c2ea6b9118d1748b43f4fdd58d17ebe453ef8e0016b5766e4
- run: yarn percy storybook storybook-static
-
avt:
if: ${{ always() }}
runs-on: ubuntu-latest
diff --git a/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.test.js b/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.test.js
index d9cf59f68f..485911ba7a 100644
--- a/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.test.js
+++ b/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.test.js
@@ -22,12 +22,18 @@ const children = `hello, world (${uuidv4()})`;
const dataTestId = uuidv4();
const className = `class-${uuidv4()}`;
-const childrenContent = (
+const childrenContent = [
-);
+ />,
+ ,
+];
const renderCoachmarkWithOverlayElements = (
{ ...rest } = {},
@@ -165,4 +171,22 @@ describe(componentName, () => {
expect(screen.getByRole('img')).toBeInTheDocument();
});
+
+ it('calls onNext', async () => {
+ const user = userEvent.setup();
+ const onNext = jest.fn();
+ renderCoachmarkWithOverlayElements({
+ 'data-testid': dataTestId,
+ onNext,
+ });
+ const beaconOrButton = screen.getByRole('button', {
+ name: 'Show information',
+ });
+ await act(() => user.click(beaconOrButton));
+ const nextButton = screen.getByRole('button', {
+ name: 'Next',
+ });
+ await act(() => user.click(nextButton));
+ await expect(onNext).toHaveBeenCalled();
+ });
});
diff --git a/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.tsx b/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.tsx
index 2db4b39812..710db555aa 100644
--- a/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.tsx
+++ b/packages/ibm-products/src/components/CoachmarkOverlayElements/CoachmarkOverlayElements.tsx
@@ -77,6 +77,18 @@ export interface CoachmarkOverlayElementsProps {
* The label for the Close button.
*/
closeButtonLabel?: string;
+ /**
+ * Callback called when clicking on the Next button.
+ */
+ onNext?: () => void;
+ /**
+ * Callback called when clicking on the Previous button.
+ */
+ onBack?: () => void;
+ /**
+ * Current step of the coachmarks.
+ */
+ currentStep?: number;
}
// NOTE: the component SCSS is not imported here: it is rolled up separately.
@@ -96,6 +108,9 @@ const defaults = {
nextButtonText: 'Next',
previousButtonLabel: 'Back',
closeButtonLabel: 'Got it',
+ onNext: undefined,
+ onBack: undefined,
+ currentStep: 0,
};
/**
* Composable container to allow for the displaying of CoachmarkOverlayElement
@@ -112,9 +127,12 @@ export let CoachmarkOverlayElements = React.forwardRef<
isVisible = defaults.isVisible,
media,
renderMedia,
+ currentStep = defaults.currentStep,
nextButtonText = defaults.nextButtonText,
previousButtonLabel = defaults.previousButtonLabel,
closeButtonLabel = defaults.closeButtonLabel,
+ onNext = defaults.onNext,
+ onBack = defaults.onBack,
// Collect any other property values passed in.
...rest
},
@@ -123,7 +141,7 @@ export let CoachmarkOverlayElements = React.forwardRef<
const buttonFocusRef = useRef | undefined>(undefined);
const scrollRef = useRef(undefined);
const [scrollPosition, setScrollPosition] = useState(0);
- const [currentProgStep, _setCurrentProgStep] = useState(0);
+ const [currentProgStep, _setCurrentProgStep] = useState(currentStep);
const coachmark = useCoachmark();
const hasMedia = media || renderMedia;
@@ -145,6 +163,16 @@ export let CoachmarkOverlayElements = React.forwardRef<
[currentProgStep, renderMedia]
);
+ useEffect(() => {
+ // When current step is set by props
+ // scroll to the appropriate view on the carrousel
+ const targetStep = clamp(currentStep, progStepFloor, progStepCeil);
+
+ scrollRef?.current?.scrollToView?.(targetStep);
+ // Avoid circular call to this hook
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [currentStep]);
+
useEffect(() => {
// On mount, one of the two primary buttons ("next" or "close")
// will be rendered and must have focus. (a11y)
@@ -222,7 +250,6 @@ export let CoachmarkOverlayElements = React.forwardRef<
) : (
<>
}
onScroll={(scrollPercent) => {
setScrollPosition(scrollPercent);
@@ -248,6 +275,7 @@ export let CoachmarkOverlayElements = React.forwardRef<
);
scrollRef?.current?.scrollToView?.(targetStep);
setCurrentProgStep(targetStep);
+ onBack?.();
}}
>
{previousButtonLabel}
@@ -268,6 +296,7 @@ export let CoachmarkOverlayElements = React.forwardRef<
);
scrollRef?.current?.scrollToView?.(targetStep);
setCurrentProgStep(targetStep);
+ onNext?.();
}}
>
{nextButtonText}
@@ -320,6 +349,10 @@ CoachmarkOverlayElements.propTypes = {
* 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.
@@ -344,6 +377,14 @@ CoachmarkOverlayElements.propTypes = {
* 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.
*/