@carbon/ibm-products
Version:
Carbon for IBM Products
695 lines (693 loc) • 28 kB
JavaScript
/**
* 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.
*/
const require_runtime = require("../../_virtual/_rolldown/runtime.js");
const require_index = require("../../node_modules/classnames/index.js");
const require_pconsole = require("../../global/js/utils/pconsole.js");
const require_settings = require("../../settings.js");
const require_usePreviousValue = require("../../global/js/hooks/usePreviousValue.js");
const require_useFocus = require("../../global/js/hooks/useFocus.js");
const require_usePresence = require("../../global/js/hooks/usePresence.js");
const require_usePrefersReducedMotion = require("../../global/js/hooks/usePrefersReducedMotion.js");
const require_devtools = require("../../global/js/utils/devtools.js");
const require_props_helper = require("../../global/js/utils/props-helper.js");
const require_index$1 = require("../FeatureFlags/index.js");
const require_ActionSet = require("../ActionSet/ActionSet.js");
const require_constants = require("./constants.js");
let react = require("react");
react = require_runtime.__toESM(react);
let prop_types = require("prop-types");
prop_types = require_runtime.__toESM(prop_types);
let _carbon_react = require("@carbon/react");
let _carbon_react_icons = require("@carbon/react/icons");
let _carbon_labs_react_resizer = require("@carbon-labs/react-resizer");
let _carbon_motion = require("@carbon/motion");
//#region src/components/SidePanel/SidePanel.tsx
/**
* 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.
*/
var import_classnames = /* @__PURE__ */ require_runtime.__toESM(require_index.default);
const blockClass = `${require_settings.pkg.prefix}--side-panel`;
const componentName = "SidePanel";
const defaults = {
animateTitle: true,
closeIconDescription: "Close",
closeIconTooltipAlignment: "left",
currentStep: 0,
hideCloseButton: false,
navigationBackIconDescription: "Back",
placement: "right",
size: "md"
};
/**
* Side panels keep users in-context of a page while performing tasks like navigating, editing, viewing details, or configuring something new.
*/
const SidePanel = react.default.forwardRef((props, ref) => {
const { actionToolbarButtons, actions, aiLabel, animateTitle = defaults.animateTitle, children, className, closeIconDescription = defaults.closeIconDescription, closeIconTooltipAlignment = defaults.closeIconTooltipAlignment, condensedActions, currentStep = defaults.currentStep, decorator, hideCloseButton = defaults.hideCloseButton, id = blockClass, includeOverlay, labelText, navigationBackIconDescription = defaults.navigationBackIconDescription, onNavigationBack, onRequestClose, onUnmount, open, placement = defaults.placement, preventCloseOnClickOutside, selectorPageContent, selectorPrimaryFocus, size = defaults.size, slideIn, slug, subtitle, title, launcherButtonRef, ...rest } = props;
const [animationComplete, setAnimationComplete] = (0, react.useState)(false);
const localRef = (0, react.useRef)(null);
const sidePanelRef = ref || localRef;
const overlayRef = (0, react.useRef)(null);
const innerContentRef = (0, react.useRef)(null);
const closeRef = (0, react.useRef)(null);
const animatedScrollRef = (0, react.useRef)(null);
const headerRef = (0, react.useRef)(null);
const titleRef = (0, react.useRef)(null);
const labelTextRef = (0, react.useRef)(null);
const subtitleRef = (0, react.useRef)(null);
const previousState = require_usePreviousValue.usePreviousValue({
size,
open,
currentStep
});
const [scrollAnimationDistance, setScrollAnimationDistance] = (0, react.useState)(-1);
const [doAnimateTitle, setDoAnimateTitle] = (0, react.useState)(true);
const { firstElement, keyDownListener } = require_useFocus.useFocus(sidePanelRef);
const panelRefValue = sidePanelRef.current;
const previousOpen = require_usePreviousValue.usePreviousValue(open);
const enableResizer = require_index$1.useFeatureFlag("enableSidepanelResizer");
const sidePanelWidth = (0, react.useRef)(void 0);
const accumulatedDeltaRef = (0, react.useRef)(0);
const shouldReduceMotion = require_usePrefersReducedMotion.usePrefersReducedMotion();
const { shouldRender } = require_usePresence.usePresence(open, sidePanelRef, shouldReduceMotion ? "side-panel-exit-reduced" : placement === "right" ? "side-panel-exit-right" : "side-panel-exit-left");
const [labelTextHeight, setLabelTextHeight] = (0, react.useState)(0);
const handleEscapeKey = (0, react.useCallback)((event) => {
if (event.key === "Escape" && open) onRequestClose?.();
}, [onRequestClose, open]);
(0, react.useEffect)(() => {
if (open && !slideIn) {
window.addEventListener("keydown", handleEscapeKey);
return () => {
window.removeEventListener("keydown", handleEscapeKey);
};
}
}, [
handleEscapeKey,
open,
slideIn
]);
(0, react.useEffect)(() => {
if (!enableResizer) return;
const parentEl = sidePanelRef.current?.parentElement;
if (parentEl) parentEl.style.removeProperty("--c4p-side-panel-modified-size");
}, [
size,
enableResizer,
sidePanelRef
]);
(0, react.useEffect)(() => {
if (!enableResizer) return;
sidePanelWidth.current = sidePanelRef?.current?.clientWidth;
}, [
sidePanelRef,
sidePanelRef?.current?.clientWidth,
enableResizer
]);
(0, react.useEffect)(() => {
if (open && !titleRef?.current) setDoAnimateTitle(false);
else setDoAnimateTitle(animateTitle);
}, [animateTitle, open]);
const onResize = (0, react.useCallback)((event, delta) => {
event.preventDefault();
event.stopPropagation();
const setWidth = (width) => {
const parentEl = sidePanelRef.current?.parentElement;
if (parentEl) parentEl.style.setProperty("--c4p-side-panel-modified-size", typeof width === "number" ? `${width}px` : width);
};
if (event.type === "keydown") {
switch (event.key) {
case "Home":
setWidth("75vw");
break;
case "End":
setWidth(require_constants.SIDE_PANEL_SIZES["xs"]);
break;
case "ArrowLeft":
case "ArrowRight":
accumulatedDeltaRef.current += delta;
setWidth((sidePanelWidth.current ?? 0) - (placement === "right" ? accumulatedDeltaRef.current : -accumulatedDeltaRef.current));
break;
}
return;
}
if (sidePanelRef.current?.style) sidePanelRef.current.style.transition = "none";
setWidth((sidePanelWidth.current ?? 0) - (placement === "right" ? delta : -delta));
}, [
placement,
sidePanelRef,
sidePanelWidth
]);
const getPanelWidthPercent = (0, react.useCallback)((customWidth) => {
if (customWidth) {
const remInPixels = parseFloat(customWidth) * parseFloat(getComputedStyle(document.documentElement).fontSize);
return Math.round(remInPixels / window.innerWidth * 100);
}
return Math.round((sidePanelRef.current?.clientWidth || 0) / window.innerWidth * 100);
}, [sidePanelRef]);
const onResizeEnd = (0, react.useCallback)((_, ref) => {
accumulatedDeltaRef.current = 0;
sidePanelRef.current?.style?.removeProperty("transition");
ref.current.setAttribute("aria-label", `side panel is covering ${getPanelWidthPercent()}% of screen`);
ref.current.setAttribute("aria-valuenow", getPanelWidthPercent());
sidePanelWidth.current = sidePanelRef.current?.clientWidth;
}, [sidePanelRef, getPanelWidthPercent]);
const onDoubleClick = (0, react.useCallback)(() => {
sidePanelWidth.current = Math.min(parseFloat(require_constants.SIDE_PANEL_SIZES[size]) * 16, window.innerWidth * .75);
const parentEl = sidePanelRef.current?.parentElement;
if (parentEl) parentEl.style.removeProperty("--c4p-side-panel-modified-size");
}, [sidePanelRef, size]);
const titleItemsStyles = (0, react.useCallback)((progress) => {
if (subtitleRef?.current) {
const subtitleEl = subtitleRef?.current;
const calculatedMargin = subtitleEl?.clientHeight * progress;
subtitleEl?.style?.setProperty("margin-top", `${-calculatedMargin}px`);
}
if (labelTextRef?.current) {
const calculatedMargin = labelTextHeight * progress;
labelTextRef?.current?.style?.setProperty("margin-top", `${-calculatedMargin}px`);
}
}, [labelTextHeight]);
(0, react.useEffect)(() => {
if (open && animateTitle && labelTextRef?.current) setLabelTextHeight(Number(labelTextRef?.current?.clientHeight || null));
}, [
animateTitle,
labelTextRef,
open
]);
const handleScroll = (0, react.useCallback)(() => {
if (doAnimateTitle && innerContentRef?.current) {
const scrollTop = innerContentRef?.current?.scrollTop;
const animationProgress = Math.min(Number(scrollTop), scrollAnimationDistance) / scrollAnimationDistance;
panelRefValue?.style.setProperty(`--${blockClass}--scroll-animation-progress`, animationProgress.toString());
titleItemsStyles(animationProgress);
}
}, [
doAnimateTitle,
panelRefValue?.style,
scrollAnimationDistance,
titleItemsStyles
]);
(0, react.useEffect)(() => {
if (sidePanelRef && panelRefValue) {
const scrollableSection = animatedScrollRef.current ?? innerContentRef.current;
if (previousState && previousState["currentStep"] !== currentStep && scrollableSection) scrollableSection.scrollTop = 0;
if (previousState && previousState["size"] !== size && scrollableSection) scrollableSection.scrollTop = 0;
}
}, [
currentStep,
sidePanelRef,
size,
previousState,
id,
panelRefValue
]);
(0, react.useEffect)(() => {
if (!title && labelText) console.warn(`${componentName}: The prop \`labelText\` was provided without a \`title\`. It is required to have a \`title\` when using the \`labelText\` prop.`);
}, [labelText, title]);
(0, react.useEffect)(() => {
if (previousOpen && !open && launcherButtonRef) setTimeout(() => {
launcherButtonRef?.current?.focus();
}, 0);
}, [
launcherButtonRef,
open,
previousOpen
]);
const checkSetDoAnimateTitle = () => {
let canDoAnimateTitle = false;
if (panelRefValue && open && animateTitle && animationComplete && titleRef?.current && title && title.length && !shouldReduceMotion) {
const titleEl = titleRef.current;
const labelHeight = labelTextRef?.current?.offsetHeight ?? 0;
const subtitleHeight = subtitleRef?.current?.offsetHeight ?? 0;
const titleVerticalBorder = actionToolbarButtons ? titleEl.offsetHeight - titleEl.clientHeight : 0;
const scrollAnimationDistance = labelHeight + subtitleHeight + titleVerticalBorder;
setScrollAnimationDistance(scrollAnimationDistance);
panelRefValue?.style.setProperty(`--${blockClass}--scroll-animation-distance`, scrollAnimationDistance.toString());
const scrollEl = innerContentRef.current;
if (scrollEl) {
const innerComputed = window?.getComputedStyle(innerContentRef.current);
const innerPaddingHeight = innerComputed ? parseFloat(innerComputed?.paddingTop) + parseFloat(innerComputed?.paddingBottom) : 0;
canDoAnimateTitle = (!!labelText || !!actionToolbarButtons || !!subtitle) && scrollEl.scrollHeight - scrollEl.clientHeight >= scrollAnimationDistance + innerPaddingHeight;
}
}
if (doAnimateTitle !== canDoAnimateTitle) setDoAnimateTitle(canDoAnimateTitle);
};
(0, react.useEffect)(() => {
if (!doAnimateTitle && sidePanelRef.current) panelRefValue?.style.setProperty(`--${blockClass}--scroll-animation-progress`, "0");
}, [
doAnimateTitle,
handleScroll,
sidePanelRef,
innerContentRef,
open,
panelRefValue?.style
]);
(0, react.useEffect)(() => {
if (panelRefValue && open && animateTitle && animationComplete && titleRef?.current && title && title.length && !shouldReduceMotion) checkSetDoAnimateTitle();
}, [
open,
doAnimateTitle,
animationComplete,
handleScroll,
title,
size,
shouldReduceMotion,
id
]);
(0, react.useEffect)(() => {
const handleOutsideClick = (event) => {
if (panelRefValue && overlayRef.current && overlayRef.current.contains(event.target) && onRequestClose) onRequestClose();
};
const bodyElement = document.body;
if (includeOverlay && open) bodyElement.style.overflow = "hidden";
else if (includeOverlay && !open) bodyElement.style.overflow = "";
if (includeOverlay && !preventCloseOnClickOutside) document.addEventListener("click", handleOutsideClick);
return () => {
const bodyElement = document.body;
bodyElement.style.overflow = "";
document.removeEventListener("click", handleOutsideClick);
};
}, [
includeOverlay,
onRequestClose,
open,
preventCloseOnClickOutside,
onUnmount,
sidePanelRef,
panelRefValue
]);
const onAnimationEnd = () => {
if (!open) onUnmount?.();
setAnimationComplete(!animationComplete);
};
(0, react.useEffect)(() => {
if (shouldReduceMotion) setAnimationComplete(true);
}, [shouldReduceMotion]);
const onAnimationStart = () => {
setAnimationComplete(false);
};
(0, react.useEffect)(() => {
if (!open && slideIn) {
const pageContentElement = selectorPageContent ? document.querySelector(selectorPageContent) : null;
if (placement && placement === "right" && pageContentElement) pageContentElement.style.marginInlineEnd = "0";
else if (pageContentElement) pageContentElement.style.marginInlineStart = "0";
}
}, [
open,
placement,
selectorPageContent,
slideIn
]);
(0, react.useEffect)(() => {
if (!open && previousState && previousState["open"] && shouldReduceMotion) onUnmount?.();
}, [
open,
onUnmount,
shouldReduceMotion,
previousState
]);
(0, react.useEffect)(() => {
if (open && slideIn) {
const pageContentElement = selectorPageContent ? document.querySelector(selectorPageContent) : null;
if (pageContentElement) pageContentElement.style.inlineSize = "auto";
else require_pconsole.default.warn("SidePanel prop `selectorPageContent` was not provided a selector that matches any element on your page. If an element is not found, the panel will render as a slide over.");
if (placement && placement === "right" && pageContentElement) {
pageContentElement.style.marginInlineEnd = "0";
pageContentElement.style.transition = !shouldReduceMotion ? `margin-inline-end ${_carbon_motion.moderate02}` : "";
pageContentElement.style.marginInlineEnd = require_constants.SIDE_PANEL_SIZES[size];
} else if (pageContentElement) {
pageContentElement.style.marginInlineStart = "0";
pageContentElement.style.transition = !shouldReduceMotion ? `margin-inline-start ${_carbon_motion.moderate02}` : "";
pageContentElement.style.marginInlineStart = require_constants.SIDE_PANEL_SIZES[size];
}
}
}, [
slideIn,
selectorPageContent,
placement,
size,
shouldReduceMotion,
open
]);
(0, react.useEffect)(() => {
if (open && animationComplete) {
if (selectorPrimaryFocus && require_useFocus.getSpecificElement(sidePanelRef?.current, selectorPrimaryFocus)) {
const primeFocusEl = require_useFocus.getSpecificElement(sidePanelRef?.current, selectorPrimaryFocus);
if (primeFocusEl && window?.getComputedStyle(primeFocusEl)?.display !== "none") setTimeout(() => primeFocusEl?.focus(), 0);
} else if (!slideIn) setTimeout(() => firstElement?.focus(), 0);
}
}, [
animationComplete,
firstElement,
open,
selectorPrimaryFocus,
sidePanelRef,
slideIn
]);
const primaryActionContainerClassNames = (0, import_classnames.default)([`${blockClass}__actions-container`, { [`${blockClass}__actions-container--condensed`]: condensedActions }]);
const mainPanelClassNames = (0, import_classnames.default)([
blockClass,
className,
`${blockClass}`,
`${blockClass}--${size}`,
{
[`${blockClass}--right-placement`]: placement === "right",
[`${blockClass}--left-placement`]: placement === "left",
[`${blockClass}--slide-in`]: slideIn,
[`${blockClass}--enable-sidepanel-resizer`]: enableResizer && window.innerWidth > 768,
[`${blockClass}--has-decorator`]: decorator,
[`${blockClass}--has-slug`]: slug,
[`${blockClass}--has-ai-label`]: aiLabel,
[`${blockClass}--condensed-actions`]: condensedActions,
[`${blockClass}--has-overlay`]: includeOverlay,
[`${blockClass}--open`]: open,
[`${blockClass}--closing`]: !open,
[`${blockClass}--reduced-motion`]: shouldReduceMotion
}
]);
const renderTitle = () => /* @__PURE__ */ react.default.createElement("div", {
className: (0, import_classnames.default)(`${blockClass}__title`, { [`${blockClass}__title--no-label`]: !labelTextRef.current }),
ref: titleRef
}, /* @__PURE__ */ react.default.createElement(_carbon_react.Heading, {
className: `${blockClass}__title-text`,
"aria-hidden": false
}, title), doAnimateTitle && !shouldReduceMotion && /* @__PURE__ */ react.default.createElement(_carbon_react.Heading, {
className: `${blockClass}__collapsed-title-text`,
"aria-hidden": true
}, title));
const renderHeader = () => {
const closeSize = actions && actions.length && /l/.test(size) ? "md" : "sm";
let normalizedDecorator;
/**
* slug is deprecated
* can remove this condition in future release
*/
if (slug && slug["type"]?.displayName === "AILabel") normalizedDecorator = react.default.cloneElement(slug, { size: "xs" });
if (aiLabel && aiLabel["type"]?.displayName === "AILabel") normalizedDecorator = react.default.cloneElement(aiLabel, { size: "xs" });
if (decorator?.["type"]?.displayName === "AILabel") normalizedDecorator = react.default.cloneElement(decorator, { size: "xs" });
return /* @__PURE__ */ react.default.createElement("div", {
className: (0, import_classnames.default)(`${blockClass}__header`, {
[`${blockClass}__header--on-detail-step`]: currentStep > 0,
[`${blockClass}__header--no-title-animation`]: !animateTitle,
[`${blockClass}__header--reduced-motion`]: shouldReduceMotion,
[`${blockClass}__header--has-title`]: title
}),
ref: headerRef
}, currentStep > 0 && /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
kind: "ghost",
size: closeSize,
align: "bottom",
label: navigationBackIconDescription,
className: `${blockClass}__navigation-back-button`,
onClick: onNavigationBack
}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.ArrowLeft, null)), title && title.length && labelText && labelText.length && /* @__PURE__ */ react.default.createElement("p", {
className: `${blockClass}__label-text`,
ref: labelTextRef
}, labelText), title && title.length && renderTitle(), (normalizedDecorator || !hideCloseButton) && /* @__PURE__ */ react.default.createElement("div", { className: `${blockClass}__decorator-and-close` }, normalizedDecorator, !hideCloseButton && /* @__PURE__ */ react.default.createElement(_carbon_react.IconButton, {
className: `${blockClass}__close-button`,
label: closeIconDescription,
onClick: onRequestClose,
onKeyDown: slideIn ? void 0 : handleEscapeKey,
ref: closeRef,
align: closeIconTooltipAlignment
}, /* @__PURE__ */ react.default.createElement(_carbon_react_icons.Close, {
size: 16,
"aria-hidden": "true",
tabIndex: "-1",
className: `${blockClass}--btn__icon`
}))), subtitle && /* @__PURE__ */ react.default.createElement("p", {
className: (0, import_classnames.default)(`${blockClass}__subtitle-text`, { [`${blockClass}__subtitle-text-no-animation-no-action-toolbar`]: !doAnimateTitle && (!actionToolbarButtons || !actionToolbarButtons.length) }),
ref: subtitleRef
}, subtitle), actionToolbarButtons && actionToolbarButtons.length && /* @__PURE__ */ react.default.createElement("div", { className: `${blockClass}__action-toolbar` }, actionToolbarButtons.map(({ label, kind, hasIconOnly = false, icon, renderIcon, tooltipPosition, tooltipAlignment, leading, disabled, className, onClick, ...rest }) => /* @__PURE__ */ react.default.createElement(_carbon_react.Button, {
...rest,
key: label,
kind: kind || "ghost",
size: "sm",
renderIcon: renderIcon || icon,
iconDescription: label,
...hasIconOnly && {
tooltipPosition: tooltipPosition || "bottom",
tooltipAlignment: tooltipAlignment || "start"
},
hasIconOnly,
disabled,
className: (0, import_classnames.default)([
`${blockClass}__action-toolbar-button`,
className,
{ [`${blockClass}__action-toolbar-leading-button`]: leading }
]),
onClick
}, leading && label))));
};
const renderMain = () => {
return /* @__PURE__ */ react.default.createElement("div", {
ref: innerContentRef,
onScroll: handleScroll,
className: (0, import_classnames.default)(`${blockClass}__inner-content`, `${blockClass}--scrolls`, `${!doAnimateTitle && !animateTitle ? `${blockClass}__inner-content--no-animated-title` : ""}`)
}, /* @__PURE__ */ react.default.createElement(_carbon_react.Layer, null, children));
};
const handleKeyDown = (event) => {
if (!slideIn) {
handleEscapeKey(event);
keyDownListener(event);
}
};
return shouldRender ? /* @__PURE__ */ react.default.createElement(react.default.Fragment, null, /* @__PURE__ */ react.default.createElement(_carbon_react.Section, {
...require_devtools.getDevtoolsProps(componentName),
...rest,
id,
className: mainPanelClassNames,
ref: sidePanelRef,
as: "aside",
"aria-label": title || rest["aria-label"],
onAnimationEnd,
onAnimationStart,
onKeyDown: handleKeyDown
}, !slideIn && enableResizer && window.innerWidth > 768 && /* @__PURE__ */ react.default.createElement(_carbon_labs_react_resizer.Resizer, {
className: `${blockClass}__resizer`,
orientation: "vertical",
"aria-valuemin": getPanelWidthPercent(require_constants.SIDE_PANEL_SIZES["xs"]),
"aria-valuemax": 75,
"aria-valuenow": getPanelWidthPercent(),
onResize,
onResizeEnd,
onDoubleClick
}), renderHeader(), renderMain(), /* @__PURE__ */ react.default.createElement(require_ActionSet.ActionSet, {
actions: actions ?? [],
className: primaryActionContainerClassNames,
size: size === "xs" ? "sm" : size
})), includeOverlay && /* @__PURE__ */ react.default.createElement("div", {
ref: overlayRef,
className: (0, import_classnames.default)(`${blockClass}__overlay`, { [`${blockClass}__overlay--closing`]: !open })
})) : null;
});
const deprecatedProps = {
/**
* **deprecated**
* **Experimental:** Provide a `Slug` component to be rendered inside the `SidePanel` component
*/
slug: prop_types.default.node,
/**
* **deprecated**
* Please use the `decorator` instead
* Optional prop that is intended for any scenario where something is being generated by AI to reinforce AI transparency, accountability, and explainability at the UI level.
*/
aiLabel: prop_types.default.node
};
SidePanel.propTypes = {
/**
* Sets the action toolbar buttons
*/
/**@ts-ignore */
actionToolbarButtons: prop_types.default.arrayOf(prop_types.default.shape({
label: prop_types.default.string,
leading: prop_types.default.bool,
icon: prop_types.default.oneOfType([prop_types.default.object, prop_types.default.func]),
onClick: prop_types.default.func,
kind: prop_types.default.oneOf([
"ghost",
"tertiary",
"secondary",
"primary"
]),
tooltipAlignment: prop_types.default.oneOf([
"top",
"right",
"bottom",
"left"
]),
tooltipPosition: prop_types.default.oneOf([
"start",
"center",
"end"
])
})),
/**
* The primary actions to be shown in the side panel. Each action is
* specified as an object with optional fields: 'label' to supply the button
* label, 'kind' to select the button kind (must be 'primary', 'secondary' or
* 'ghost'), 'tooltipPosition' to select where the tooltip is placed around
* the button (must be 'top', 'right', 'bottom', or 'left'), 'tooltipAlignment'
* to select how the tooltip is aligned with the button (must be 'start',
* 'center', or 'end', 'loading' to display a loading indicator, and 'onClick' to
* receive notifications when the button is clicked. Additional fields in the
* object will be passed to the Button component, and these can include
* 'disabled', 'ref', 'className', and any other Button props. Any other
* fields in the object will be passed through to the button element as HTML
* attributes.
*
* See https://react.carbondesignsystem.com/?path=/docs/components-button--default#component-api
*/
actions: require_props_helper.allPropTypes([prop_types.default.arrayOf(prop_types.default.shape({
..._carbon_react.Button.propTypes,
kind: prop_types.default.oneOf([
"ghost",
"danger--ghost",
"secondary",
"danger",
"primary"
]),
tooltipPosition: prop_types.default.oneOf([
"top",
"right",
"bottom",
"left"
]),
tooltipAlignment: prop_types.default.oneOf([
"start",
"center",
"end"
]),
label: prop_types.default.string,
loading: prop_types.default.bool,
/**@ts-ignore */
onClick: _carbon_react.Button.propTypes.onClick
}))]),
/**
* Determines if the title will animate on scroll
*/
animateTitle: prop_types.default.bool,
/**
* Sets the body content of the side panel
*/
children: prop_types.default.oneOfType([prop_types.default.arrayOf(prop_types.default.node), prop_types.default.node]).isRequired,
/**
* Sets an optional className to be added to the side panel outermost element
*/
className: prop_types.default.string,
/**
* Sets the close button icon description
*/
closeIconDescription: prop_types.default.string,
/**
* Sets the close button tooltip alignment
*/
closeIconTooltipAlignment: prop_types.default.string,
/**
* Determines whether the side panel should render the condensed version (affects action buttons primarily)
*/
condensedActions: prop_types.default.bool,
/**
* Sets the current step of the side panel
*/
currentStep: prop_types.default.number,
/**
* Show/hide the "X" close button.
*/
hideCloseButton: prop_types.default.bool,
/**
* Unique identifier
*/
id: prop_types.default.string,
/**
* Determines whether the side panel should render with an overlay
*/
includeOverlay: prop_types.default.bool,
/**
* Sets the label text which will display above the title text
*/
labelText: prop_types.default.string,
/**
* Provide a ref to return focus to once the modal is closed.
*/
/**@ts-ignore */
launcherButtonRef: prop_types.default.any,
/**
* Sets the icon description for the navigation back icon button
*/
navigationBackIconDescription: prop_types.default.string,
/**
* Changes the current side panel page to the previous page
*/
onNavigationBack: prop_types.default.func,
/**
* Specify a handler for closing the side panel.
* This handler closes the modal, e.g. changing `open` prop.
*/
onRequestClose: prop_types.default.func,
/**
* Optional function called when the side panel exit animation is complete.
* This handler can be used for any state cleanup needed before the panel is removed from the DOM.
*/
onUnmount: prop_types.default.func,
/**
* Determines whether the side panel should render or not
*/
open: prop_types.default.bool.isRequired,
/**
* Determines if the side panel is on the right or left
*/
placement: prop_types.default.oneOf(["left", "right"]),
/**
* Prevent closing on click outside of the panel
*/
preventCloseOnClickOutside: prop_types.default.bool,
/**
* This is the selector to the element that contains all of the page content that will shrink if the panel is a slide in.
* This prop is required when using the `slideIn` variant of the side panel.
*/
/**@ts-ignore*/
selectorPageContent: prop_types.default.string,
/**
* Specify a CSS selector that matches the DOM element that should
* be focused when the side panel opens
*/
/**@ts-ignore*/
selectorPrimaryFocus: prop_types.default.string,
/**
* Sets the size of the side panel
*/
/**@ts-ignore*/
size: prop_types.default.oneOf([
"xs",
"sm",
"md",
"lg",
"xl",
"2xl"
]),
/**
* Determines if this panel slides in
*/
/**@ts-ignore*/
slideIn: prop_types.default.bool,
/**
* Sets the subtitle text
*/
subtitle: prop_types.default.node,
/**
* Sets the title text
*/
/**@ts-ignore*/
title: prop_types.default.string,
...deprecatedProps
};
SidePanel.displayName = componentName;
//#endregion
exports.SidePanel = SidePanel;