Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import React, {
ReactNode,
RefAttributes,
RefObject,
createContext,
forwardRef,
useEffect,
useRef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ const CoachmarkContent = forwardRef<HTMLDivElement, CoachmarkContentProps>(
const targetId = open ? triggerRef?.current?.id : null;

const handleRef = useRef<HTMLDivElement | null>(null);
const bubbleRef = ref && typeof ref !== 'function' ? ref : handleRef;
const bubbleRef = ref || handleRef;

useEffect(() => {
if (open && bubbleRef.current) {
if (open && 'current' in bubbleRef && bubbleRef.current) {
requestAnimationFrame(() => {
const contentBody = bubbleRef.current?.querySelector(
`.${contentBodyClass}`
Expand All @@ -91,7 +91,8 @@ const CoachmarkContent = forwardRef<HTMLDivElement, CoachmarkContentProps>(
useEffect(() => {
const handleOutsideClick = (event: MouseEvent) => {
const targetElement = document.getElementById(targetId || '');
const bubbleElement = bubbleRef.current;
const bubbleElement =
bubbleRef && 'current' in bubbleRef ? bubbleRef.current : null;

if (
bubbleElement &&
Expand Down Expand Up @@ -122,7 +123,7 @@ const CoachmarkContent = forwardRef<HTMLDivElement, CoachmarkContentProps>(
}, [open, targetId, setOpen]);

useEffect(() => {
if (open && bubbleRef.current) {
if (open && 'current' in bubbleRef && bubbleRef.current) {
const dragContainer = bubbleRef.current.querySelector(
`.${pkg.prefix}__bubble`
);
Expand All @@ -131,7 +132,8 @@ const CoachmarkContent = forwardRef<HTMLDivElement, CoachmarkContentProps>(
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, bubbleRef.current]);
}, [open, bubbleRef]);

return (
open && (
<div ref={bubbleRef}>
Expand Down
36 changes: 26 additions & 10 deletions packages/ibm-products/src/global/js/utils/carousel/carousel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ export const initCarousel = (

const minHeight = 4; // 10 rem

const { onViewChangeStart, onViewChangeEnd, excludeSwipeSupport } =
config || {};
const {
onViewChangeStart,
onViewChangeEnd,
excludeSwipeSupport,
useMaxHeight,
} = config || {};

/**
* Registers an HTMLElement at a specific index in the refs array.
Expand Down Expand Up @@ -238,6 +242,8 @@ export const initCarousel = (
*/
const performAnimation = (isInitial: boolean) => {
let itemHeightSmallest = 0;
let itemHeightMaximum = 0;

Array.from(viewItems).forEach((viewItem: HTMLElement, index) => {
const stackIndex = viewIndexStack.findIndex((idx) => idx === index);
const stackIndexInstanceCount = previousViewIndexStack.filter(
Expand Down Expand Up @@ -269,15 +275,25 @@ export const initCarousel = (
registerRef(index, viewItem);

setTimeout(() => {
if (
!itemHeightSmallest ||
(viewItem.offsetHeight < itemHeightSmallest &&
itemHeightSmallest > remToPx(minHeight))
) {
itemHeightSmallest = viewItem.offsetHeight;
if (useMaxHeight) {
const heights: number[] = Array.from(viewItems).map(
(viewItem) => viewItem.scrollHeight
);
itemHeightMaximum = Math.max(...heights);

viewItem.style.position = 'absolute';
updateHeightForWrapper(itemHeightMaximum);
} else {
if (
!itemHeightSmallest ||
(viewItem.offsetHeight < itemHeightSmallest &&
itemHeightSmallest > remToPx(minHeight))
) {
itemHeightSmallest = viewItem.offsetHeight;
}
viewItem.style.position = 'absolute';
updateHeightForWrapper(itemHeightSmallest);
}
viewItem.style.position = 'absolute';
updateHeightForWrapper(itemHeightSmallest);
});

const listener = (e: Event) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export type Config = {
onViewChangeStart?: (args: CarouselResponse) => void;
onViewChangeEnd?: (args: CarouselResponse) => void;
excludeSwipeSupport?: boolean;
useMaxHeight?: boolean;
};

interface InitCarousel {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Story, Controls, Source, Canvas } from '@storybook/addon-docs/blocks';
import { CodesandboxLink } from '../../global/js/utils/story-helper';
import * as CoachmarkStackedStories from './CoachmarkStacked.stories';
import { stackblitzPrefillConfig } from '../../../previewer/codePreviewer';

# CoachmarkStacked

## Table of Contents

- [Overview](#overview)
- [Example usage](#example-usage)

## Overview

The CoachmarkStacked pattern acts as a container element for onboarding and
should only be used within the scope of a Coachmark.

To build this pattern, we recommend including the following components:

- [Coachmark](https://carbon-for-ibm-products.netlify.app/?path=/docs/experimental-onboarding-coachmark-next--overview)
- [cds-button](https://web-components.carbondesignsystem.com/?path=/docs/components-button)
- [Carousel utility](https://github.com/carbon-design-system/carbon/blob/main/packages/utilities/src/carousel/README.md)

## About Onboarding

[Onboarding](https://pages.github.ibm.com/security/security-design/department/end-to-end-experiences/onboarding/overview/)
is a continuous learning methodology and framework that aims to orient, onboard,
explain, educate, and cultivate novice users into high-functioning power users.

## Example usage

{/* TODO: One example per designed use case. */}

<Canvas className="coachmarkExample" withSource="none">
<div className="CoachmarkBaseExampleUsage">
<Story of={CoachmarkStackedStories.CoachmarkStacked} />
</div>
</Canvas>
Loading