@@ -336,7 +342,13 @@ export let InterstitialScreen = React.forwardRef(
{isMultiStep ? (
-
+ {
+ scrollPercent === 0 && setProgStep(0);
+ }}
+ >
{children}
diff --git a/packages/ibm-products/src/components/InterstitialScreen/InterstitialScreen.stories.js b/packages/ibm-products/src/components/InterstitialScreen/InterstitialScreen.stories.js
index b4b5165726..b931a18578 100644
--- a/packages/ibm-products/src/components/InterstitialScreen/InterstitialScreen.stories.js
+++ b/packages/ibm-products/src/components/InterstitialScreen/InterstitialScreen.stories.js
@@ -300,21 +300,21 @@ interstitialScreenModalMultiplesHeader.args = {
diff --git a/packages/ibm-products/src/components/Tearsheet/TearsheetNarrow.tsx b/packages/ibm-products/src/components/Tearsheet/TearsheetNarrow.tsx
index ae37e4fa60..69861357e3 100644
--- a/packages/ibm-products/src/components/Tearsheet/TearsheetNarrow.tsx
+++ b/packages/ibm-products/src/components/Tearsheet/TearsheetNarrow.tsx
@@ -6,7 +6,7 @@
*/
// Import portions of React that are needed.
-import React, { ReactNode, PropsWithChildren } from 'react';
+import React, { ReactNode, PropsWithChildren, ForwardedRef } from 'react';
// Other standard imports.
import PropTypes from 'prop-types';
@@ -25,16 +25,12 @@ import {
tearsheetHasCloseIcon,
TearsheetShell,
tearsheetShellWideProps as blocked,
+ CloseIconDescriptionTypes,
} from './TearsheetShell';
import { portalType } from './TearsheetShell';
-type closeIconDescriptionTypes = {
- hasCloseIcon: true;
- closeIconDescription: string;
-};
-
-interface TearsheetNarrowProps extends PropsWithChildren {
+interface TearsheetNarrowBaseProps extends PropsWithChildren {
/**
* The navigation actions to be shown as buttons in the action area at the
* bottom of the tearsheet. Each action is specified as an object with
@@ -61,14 +57,6 @@ interface TearsheetNarrowProps extends PropsWithChildren {
*/
className?: string;
- /**
- * The accessibility title for the close icon (if shown).
- *
- * **Note:** This prop is only required if a close icon is shown, i.e. if
- * there are a no navigation actions and/or hasCloseIcon is true.
- */
- closeIconDescription?: closeIconDescriptionTypes;
-
/**
* A description of the flow, displayed in the header area of the tearsheet.
*/
@@ -123,6 +111,9 @@ interface TearsheetNarrowProps extends PropsWithChildren {
verticalPosition?: 'normal' | 'lower';
}
+type TearsheetNarrowProps = TearsheetNarrowBaseProps &
+ CloseIconDescriptionTypes;
+
const componentName = 'TearsheetNarrow';
// NOTE: the component SCSS is not imported here: it is rolled up separately.
@@ -147,7 +138,7 @@ export let TearsheetNarrow = React.forwardRef(
verticalPosition = defaults.verticalPosition,
...rest
}: TearsheetNarrowProps,
- ref
+ ref: ForwardedRef
) => (
void;
+
+ /**
+ * Specifies whether the tearsheet is currently open.
+ */
+ open?: boolean;
+
+ /**
+ * The DOM element that the tearsheet should be rendered within. Defaults to document.body.
+ */
+ portalTarget?: ReactNode;
+
+ selectorPrimaryFocus?: string;
+
+ /**
+ * Specifies the width of the tearsheet, 'narrow' or 'wide'.
+ */
+ size: 'narrow' | 'wide';
+
+ /**
+ * **Experimental:** Provide a `Slug` component to be rendered inside the `Tearsheet` component
+ */
+ slug?: ReactNode;
+
+ /**
+ * The main title of the tearsheet, displayed in the header area.
+ */
+ title?: ReactNode;
+
+ verticalPosition?: 'normal' | 'lower';
+}
+
+export type CloseIconDescriptionTypes =
+ | {
+ hasCloseIcon?: false;
+ closeIconDescription?: string;
+ }
+ | {
+ hasCloseIcon: true;
+ closeIconDescription: string;
+ };
+
// NOTE: the component SCSS is not imported here: it is rolled up separately.
// Global data structure to communicate the state of tearsheet stacking
@@ -47,7 +169,20 @@ const maxDepth = 3;
// The 'sizes' array contains an array of the sizes for every stacked tearsheet.
// This is so we can opt-out of including the stacking scale effect when there
// are stacked tearsheets with mixed sizes (ie, using wide and narrow together)
-const stack = { open: [], all: [], sizes: [] };
+type stackTypes = {
+ open: Array<{
+ (a: number, b: number): void;
+ checkFocus?: () => void;
+ claimFocus?: () => void;
+ }>;
+ all: Array<{
+ (a: number, b: number): void;
+ checkFocus?: () => void;
+ claimFocus?: () => void;
+ }>;
+ sizes: Array;
+};
+const stack: stackTypes = { open: [], all: [], sizes: [] };
// these props are only applicable when size='wide'
export const tearsheetShellWideProps = [
@@ -96,8 +231,8 @@ export const TearsheetShell = React.forwardRef(
verticalPosition,
// Collect any other property values passed in.
...rest
- },
- ref
+ }: TearsheetShellProps & CloseIconDescriptionTypes,
+ ref: ForwardedRef
) => {
const carbonPrefix = usePrefix();
const bcModalHeader = `${carbonPrefix}--modal-header`;
@@ -108,6 +243,8 @@ export const TearsheetShell = React.forwardRef(
const modalRef = ref || localRef;
const { width } = useResizeObserver(resizer);
const { firstElement, keyDownListener } = useFocus(modalRef);
+ const modalRefValue = (modalRef as MutableRefObject)
+ .current;
const wide = size === 'wide';
@@ -116,7 +253,7 @@ export const TearsheetShell = React.forwardRef(
const [position, setPosition] = useState(0);
// Keep a record of the previous value of depth.
- const prevDepth = useRef();
+ const prevDepth = useRef();
useEffect(() => {
prevDepth.current = depth;
});
@@ -127,7 +264,7 @@ export const TearsheetShell = React.forwardRef(
// Callback that will be called whenever the stacking order changes.
// position is 1-based with 0 indicating closed.
- function handleStackChange(newDepth, newPosition) {
+ function handleStackChange(newDepth: number, newPosition: number) {
setDepth(newDepth);
setPosition(newPosition);
}
@@ -137,8 +274,8 @@ export const TearsheetShell = React.forwardRef(
if (
open &&
position === depth &&
- modalRef.current &&
- !modalRef.current.contains(document.activeElement)
+ modalRefValue &&
+ !modalRefValue.contains(document.activeElement)
) {
handleStackChange.claimFocus();
}
@@ -174,7 +311,7 @@ export const TearsheetShell = React.forwardRef(
Math.min(stack.open.length, maxDepth),
stack.open.indexOf(handler) + 1
);
- handler.checkFocus();
+ handler.checkFocus?.();
});
// Register this tearsheet's stack change callback/listener.
@@ -213,7 +350,7 @@ export const TearsheetShell = React.forwardRef(
// If something within us is receiving focus but we are not the topmost
// stacked tearsheet, transfer focus to the topmost tearsheet instead
if (position < depth) {
- stack.open[stack.open.length - 1].claimFocus();
+ stack.open[stack.open.length - 1].claimFocus?.();
}
}
@@ -257,7 +394,7 @@ export const TearsheetShell = React.forwardRef(
className={cx(bc, className, {
[`${bc}--stacked-${position}-of-${depth}`]:
// Don't apply this on the initial open of a single tearsheet.
- depth > 1 || (depth === 1 && prevDepth.current > 1),
+ depth > 1 || (depth === 1 && (prevDepth?.current ?? 0) > 1),
[`${bc}--wide`]: wide,
[`${bc}--narrow`]: !wide,
[`${bc}--has-slug`]: slug,
@@ -339,7 +476,9 @@ export const TearsheetShell = React.forwardRef(
{children}
@@ -357,7 +496,7 @@ export const TearsheetShell = React.forwardRef(
tearsheetHasCloseIcon(actions, hasCloseIcon)
),
@@ -470,6 +611,7 @@ TearsheetShell.propTypes = {
* tearsheet"), and that behavior can be overridden if required by setting
* this prop to either true or false.
*/
+ /**@ts-ignore*/
hasCloseIcon: PropTypes.bool,
/**
@@ -528,11 +670,13 @@ TearsheetShell.propTypes = {
/**
* The DOM element that the tearsheet should be rendered within. Defaults to document.body.
*/
+ /**@ts-ignore*/
portalTarget: portalType,
/**
* Specifies the width of the tearsheet, 'narrow' or 'wide'.
*/
+ /**@ts-ignore*/
size: PropTypes.oneOf(['narrow', 'wide']).isRequired,
/**
diff --git a/packages/ibm-products/src/components/Toolbar/Toolbar.tsx b/packages/ibm-products/src/components/Toolbar/Toolbar.tsx
index de57e8436f..6445717d14 100644
--- a/packages/ibm-products/src/components/Toolbar/Toolbar.tsx
+++ b/packages/ibm-products/src/components/Toolbar/Toolbar.tsx
@@ -26,8 +26,6 @@ const { checkComponentEnabled, prefix } = pkg;
const blockClass = `${prefix}--toolbar`;
interface ToolbarProps {
-
-
/** Provide an optional class to be applied to the containing node */
className?: string;
@@ -47,14 +45,13 @@ let Toolbar = forwardRef(
{ children, className, vertical, ...rest }: PropsWithChildren,
r: React.Ref
) => {
- const focusableElements = useRef();
+ const focusableElements = useRef();
const getFocusableElements = useCallback(
- (): HTMLElement[]|undefined => focusableElements.current,
+ (): HTMLElement[] | undefined => focusableElements.current,
[focusableElements]
);
-
const localRef = useRef(null);
const ref = r || localRef;
@@ -65,7 +62,7 @@ let Toolbar = forwardRef(
ref?.['current']
) as HTMLElement[];
- focus !== -1 &&
+ focus !== -1 &&
getFocusableElements()?.forEach((element, index) => {
element[index !== focus ? 'setAttribute' : 'removeAttribute'](
'tabindex',
@@ -75,14 +72,14 @@ let Toolbar = forwardRef(
});
useEffect(() => {
- focus !== -1 && getFocusableElements()?.[focus].focus();
+ focus !== -1 && getFocusableElements()?.[focus].focus();
}, [focus, getFocusableElements]);
const [arrowNext, arrowPrevious] = !vertical
? ['ArrowRight', 'ArrowLeft']
: ['ArrowDown', 'ArrowUp'];
- function onArrowDown(increment:number) {
+ function onArrowDown(increment: number) {
const nextFocus = focus + increment;
getFocusableElements()?.[nextFocus] && setFocus(nextFocus);
@@ -111,7 +108,7 @@ let Toolbar = forwardRef(
return (
{
return result;
};
-// Default values for props
-const defaults = {
- element: 'div',
-};
+interface WrapProps extends PropsWithChildren {
+ /**
+ * Specify whether the wrapper element should render even if there are no
+ * children or the children are themselves empty wrappers. Useful if there
+ * are some conditions in which the wrapper element is still required. Note
+ * that this prop takes precedence over neverRender if both are set to true.
+ */
+ alwaysRender?: boolean | null;
+
+ /**
+ * The element name or component to use as a wrapper for the content.
+ */
+ element?: (() => ReactNode) | string | ElementType;
+
+ /**
+ * Specify whether nothing should be rendered even if there are children
+ * in the content. Useful if there are some circumstances in which the
+ * component should not render at all. Note that if alwaysRender is also
+ * set to true then it will take precedence and the wrapper element and
+ * content will be rendered.
+ */
+ neverRender?: boolean;
+
+ className?: string;
+}
/**
* A simple conditional wrapper that encloses its children in a
(or other
@@ -47,16 +73,17 @@ export const Wrap = React.forwardRef(
alwaysRender,
children,
- element: Wrapper = defaults.element,
+ element: Wrapper = 'div',
neverRender,
+ className,
// Collect any other property values passed in.
...rest
- },
- ref
+ }: WrapProps,
+ ref: ForwardedRef
) =>
(neverRender || isEmpty(children)) && !alwaysRender ? null : (
-
+
{children}
)
@@ -80,6 +107,8 @@ Wrap.propTypes = {
*/
children: PropTypes.node,
+ className: PropTypes.string,
+
/**
* The element name or component to use as a wrapper for the content.
*/
diff --git a/packages/ibm-products/src/global/js/utils/getNodeTextContent.js b/packages/ibm-products/src/global/js/utils/getNodeTextContent.js
index 94e70d3d4c..8511d49eb8 100644
--- a/packages/ibm-products/src/global/js/utils/getNodeTextContent.js
+++ b/packages/ibm-products/src/global/js/utils/getNodeTextContent.js
@@ -16,7 +16,7 @@
* Item 3
*
* --> "Item 1Item 2Item 3"
- * @param {Node} node A React node
+ * @param {ReactNode} node A React node
* @returns {string}
*/
export const getNodeTextContent = (node) => {