@mskcc/carbon-react
Version:
Carbon react components for the MSKCC DSM
848 lines (813 loc) • 29.3 kB
JavaScript
/**
* MSKCC 2021, 2024
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var _rollupPluginBabelHelpers = require('../../_virtual/_rollupPluginBabelHelpers.js');
var iconsReact = require('@carbon/icons-react');
var layout = require('@carbon/layout');
var cx = require('classnames');
var debounce = require('lodash.debounce');
var PropTypes = require('prop-types');
var React = require('react');
var reactIs = require('react-is');
require('../Tooltip/DefinitionTooltip.js');
var Tooltip = require('../Tooltip/Tooltip.js');
var useControllableState = require('../../internal/useControllableState.js');
var useEffectOnce = require('../../internal/useEffectOnce.js');
var useId = require('../../internal/useId.js');
var useIsomorphicEffect = require('../../internal/useIsomorphicEffect.js');
var useMergedRefs = require('../../internal/useMergedRefs.js');
var useNoInteractiveChildren = require('../../internal/useNoInteractiveChildren.js');
var usePrefix = require('../../internal/usePrefix.js');
var usePressable = require('./usePressable.js');
var deprecate = require('../../prop-types/deprecate.js');
var useEvent = require('../../internal/useEvent.js');
var useMatchMedia = require('../../internal/useMatchMedia.js');
var match = require('../../internal/keyboard/match.js');
var keys = require('../../internal/keyboard/keys.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var cx__default = /*#__PURE__*/_interopDefaultLegacy(cx);
var debounce__default = /*#__PURE__*/_interopDefaultLegacy(debounce);
var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
var _ChevronLeft, _ChevronRight, _Close;
// Used to manage the overall state of the Tabs
const TabsContext = /*#__PURE__*/React__default["default"].createContext({
baseId: '',
activeIndex: 0,
defaultSelectedIndex: 0,
dismissable: false,
onTabCloseRequest() {},
setActiveIndex() {},
selectedIndex: 0,
setSelectedIndex() {}
});
// Used to keep track of position in a tablist
const TabContext = /*#__PURE__*/React__default["default"].createContext({
index: 0,
hasSecondaryLabel: false
});
const lgMediaQuery = `(min-width: ${layout.breakpoints.lg.width})`;
// Used to keep track of position in a list of tab panels
const TabPanelContext = /*#__PURE__*/React__default["default"].createContext(0);
/**
* Tabs
*/
function Tabs(_ref) {
let {
children,
defaultSelectedIndex = 0,
onChange,
selectedIndex: controlledSelectedIndex,
dismissable,
onTabCloseRequest
} = _ref;
const baseId = useId.useId('ccs');
// The active index is used to track the element which has focus in our tablist
const [activeIndex, setActiveIndex] = React.useState(defaultSelectedIndex);
// The selected index is used for the tab/panel pairing which is "visible"
const [selectedIndex, setSelectedIndex] = useControllableState.useControllableState({
value: controlledSelectedIndex,
defaultValue: defaultSelectedIndex,
onChange: value => onChange?.({
selectedIndex: value
})
});
const value = {
baseId,
activeIndex,
defaultSelectedIndex,
dismissable,
onTabCloseRequest,
setActiveIndex,
selectedIndex,
setSelectedIndex
};
return /*#__PURE__*/React__default["default"].createElement(TabsContext.Provider, {
value: value
}, children);
}
Tabs.propTypes = {
/**
* Provide child elements to be rendered inside the `Tabs`.
* These elements should render either `TabsList` or `TabsPanels`
*/
children: PropTypes__default["default"].node,
/**
* Specify which content tab should be initially selected when the component
* is first rendered
*/
defaultSelectedIndex: PropTypes__default["default"].number,
/**
* Whether the render Tab children should be dismissable.
*/
dismissable: PropTypes__default["default"].bool,
/**
* Provide an optional function which is called whenever the state of the
* `Tabs` changes
*/
onChange: PropTypes__default["default"].func,
/**
* If specifying the `onTabCloseRequest` prop, provide a callback function
* responsible for removing the tab when close button is pressed on one of the Tab elements
*/
onTabCloseRequest: props => {
if (props.dismissable && !props.onTabCloseRequest) {
return new Error('dismissable property specified without also providing an onTabCloseRequest property.');
}
return undefined;
},
/**
* Control which content panel is currently selected. This puts the component
* in a controlled mode and should be used along with `onChange`
*/
selectedIndex: PropTypes__default["default"].number
};
/**
* Get the next index for a given keyboard event
* given a count of the total items and the current index
*/
function getNextIndex(event, total, index) {
switch (true) {
case match.match(event, keys.ArrowRight):
return (index + 1) % total;
case match.match(event, keys.ArrowLeft):
return (total + index - 1) % total;
case match.match(event, keys.Home):
return 0;
case match.match(event, keys.End):
return total - 1;
default:
return index;
}
}
/**
* TabList
*/
function TabList(_ref2) {
let {
activation = 'automatic',
'aria-label': label,
children,
className: customClassName,
contained = false,
fullWidth = false,
iconSize,
leftOverflowButtonProps,
light,
rightOverflowButtonProps,
scrollDebounceWait = 200,
scrollIntoView,
...rest
} = _ref2;
const {
activeIndex,
selectedIndex,
setSelectedIndex,
setActiveIndex,
dismissable
} = React__default["default"].useContext(TabsContext);
const prefix = usePrefix.usePrefix();
const ref = React.useRef(null);
const previousButton = React.useRef(null);
const nextButton = React.useRef(null);
const [isScrollable, setIsScrollable] = React.useState(false);
const [scrollLeft, setScrollLeft] = React.useState(0);
let hasSecondaryLabelTabs = false;
if (contained) {
hasSecondaryLabelTabs = React__default["default"].Children.toArray(children).some(child => {
return reactIs.isElement(child) && !!child.props.secondaryLabel;
});
}
const isLg = useMatchMedia.useMatchMedia(lgMediaQuery);
const distributeWidth = fullWidth && contained && isLg && React__default["default"].Children.toArray(children).length < 9;
const className = cx__default["default"](`${prefix}--tabs`, {
[`${prefix}--tabs--contained`]: contained,
[`${prefix}--tabs--light`]: light,
[`${prefix}--tabs__icon--default`]: iconSize === 'default',
[`${prefix}--tabs__icon--lg`]: iconSize === 'lg',
// TODO: V12 - Remove this class
[`${prefix}--layout--size-lg`]: iconSize === 'lg',
[`${prefix}--tabs--tall`]: hasSecondaryLabelTabs,
[`${prefix}--tabs--full-width`]: distributeWidth
}, customClassName);
// Previous Button
// VISIBLE IF:
// SCROLLABLE
// AND SCROLL_LEFT > 0
const buttonWidth = 44;
// Next Button
// VISIBLE IF:
// SCROLLABLE
// AND SCROLL_LEFT + CLIENT_WIDTH < SCROLL_WIDTH
const [isNextButtonVisible, setIsNextButtonVisible] = React.useState(ref.current ? scrollLeft + buttonWidth + ref.current.clientWidth < ref.current.scrollWidth : false);
const isPreviousButtonVisible = ref.current ? isScrollable && scrollLeft > 0 : false;
const previousButtonClasses = cx__default["default"](`${prefix}--tab--overflow-nav-button`, `${prefix}--tab--overflow-nav-button--previous`, {
[`${prefix}--tab--overflow-nav-button--hidden`]: !isPreviousButtonVisible
});
const nextButtonClasses = cx__default["default"](`${prefix}--tab--overflow-nav-button`, `${prefix}--tab--overflow-nav-button--next`, {
[`${prefix}--tab--overflow-nav-button--hidden`]: !isNextButtonVisible
});
const tabs = React.useRef([]);
const debouncedOnScroll = React.useCallback(() => {
return debounce__default["default"](event => {
setScrollLeft(event.target.scrollLeft);
}, scrollDebounceWait);
}, [scrollDebounceWait]);
function onKeyDown(event) {
if (match.matches(event, [keys.ArrowRight, keys.ArrowLeft, keys.Home, keys.End])) {
event.preventDefault();
const activeTabs = tabs.current.filter(tab => !tab.disabled);
const currentIndex = activeTabs.indexOf(tabs.current[activation === 'automatic' ? selectedIndex : activeIndex]);
const nextIndex = tabs.current.indexOf(activeTabs[getNextIndex(event, activeTabs.length, currentIndex)]);
if (activation === 'automatic') {
setSelectedIndex(nextIndex);
} else if (activation === 'manual') {
setActiveIndex(nextIndex);
}
tabs.current[nextIndex]?.focus();
}
}
useEffectOnce.useEffectOnce(() => {
const tab = tabs.current[selectedIndex];
if (scrollIntoView && tab) {
tab.scrollIntoView({
block: 'nearest',
inline: 'nearest'
});
}
});
React.useEffect(() => {
setIsNextButtonVisible(ref.current ? scrollLeft + buttonWidth + ref.current.clientWidth < ref.current.scrollWidth : false);
if (dismissable) {
if (ref.current) {
setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth);
}
}
}, [scrollLeft, children, dismissable]);
useEffectOnce.useEffectOnce(() => {
if (tabs.current[selectedIndex].disabled) {
const activeTabs = tabs.current.filter(tab => {
return !tab.disabled;
});
if (activeTabs.length > 0) {
const tab = activeTabs[0];
setSelectedIndex(tabs.current.indexOf(tab));
}
}
});
useIsomorphicEffect["default"](() => {
if (ref.current) {
setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth);
}
function handler() {
if (ref.current) {
setIsScrollable(ref.current.scrollWidth > ref.current.clientWidth);
}
}
const debouncedHandler = debounce__default["default"](handler, 200);
window.addEventListener('resize', debouncedHandler);
return () => {
debouncedHandler.cancel();
window.removeEventListener('resize', debouncedHandler);
};
}, []);
// updates scroll location for all scroll behavior.
useIsomorphicEffect["default"](() => {
if (scrollLeft !== null && ref.current) {
ref.current.scrollLeft = scrollLeft;
}
}, [scrollLeft]);
useIsomorphicEffect["default"](() => {
if (!isScrollable || !ref.current) {
return;
}
const tab = activation === 'manual' ? tabs.current[activeIndex] : tabs.current[selectedIndex];
if (tab) {
// The width of the "scroll buttons"
// The start and end position of the selected tab
const {
width: tabWidth
} = tab.getBoundingClientRect();
const start = tab.offsetLeft;
const end = tab.offsetLeft + tabWidth;
// The start and end of the visible area for the tabs
const visibleStart = ref.current.scrollLeft + buttonWidth;
const visibleEnd = ref.current.scrollLeft + ref.current.clientWidth - buttonWidth;
// The beginning of the tab is clipped and not visible
if (start < visibleStart) {
setScrollLeft(start - buttonWidth);
}
// The end of the tab is clipped and not visible
if (end > visibleEnd) {
setScrollLeft(end + buttonWidth - ref.current.clientWidth);
}
}
}, [activation, activeIndex, selectedIndex, isScrollable, children]);
usePressable.usePressable(previousButton, {
onPress(_ref3) {
let {
longPress
} = _ref3;
if (!longPress && ref.current) {
setScrollLeft(Math.max(scrollLeft - ref.current.scrollWidth / tabs.current.length * 1.5, 0));
}
},
onLongPress() {
return createLongPressBehavior(ref, 'backward', setScrollLeft);
}
});
usePressable.usePressable(nextButton, {
onPress(_ref4) {
let {
longPress
} = _ref4;
if (!longPress && ref.current) {
setScrollLeft(Math.min(scrollLeft + ref.current.scrollWidth / tabs.current.length * 1.5, ref.current.scrollWidth - ref.current.clientWidth));
}
},
onLongPress() {
return createLongPressBehavior(ref, 'forward', setScrollLeft);
}
});
return /*#__PURE__*/React__default["default"].createElement("div", {
className: className
}, /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({
"aria-hidden": "true",
tabIndex: -1,
"aria-label": "Scroll left",
ref: previousButton,
className: previousButtonClasses,
type: "button"
}, leftOverflowButtonProps), _ChevronLeft || (_ChevronLeft = /*#__PURE__*/React__default["default"].createElement(iconsReact.ChevronLeft, null))), /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
"aria-label": label,
ref: ref,
role: "tablist",
className: `${prefix}--tab--list`,
onScroll: debouncedOnScroll,
onKeyDown: onKeyDown
}), React__default["default"].Children.map(children, (child, index) => {
return !reactIs.isElement(child) ? null : /*#__PURE__*/React__default["default"].createElement(TabContext.Provider, {
value: {
index,
hasSecondaryLabel: hasSecondaryLabelTabs,
contained
}
}, /*#__PURE__*/React__default["default"].cloneElement(child, {
ref: node => {
tabs.current[index] = node;
}
}));
})), /*#__PURE__*/React__default["default"].createElement("button", _rollupPluginBabelHelpers["extends"]({
"aria-hidden": "true",
tabIndex: -1,
"aria-label": "Scroll right",
ref: nextButton,
className: nextButtonClasses,
type: "button"
}, rightOverflowButtonProps), _ChevronRight || (_ChevronRight = /*#__PURE__*/React__default["default"].createElement(iconsReact.ChevronRight, null))));
}
TabList.propTypes = {
/**
* Specify whether the content tab should be activated automatically or
* manually
*/
activation: PropTypes__default["default"].oneOf(['automatic', 'manual']),
/**
* Provide an accessible label to be read when a user interacts with this
* component
*/
'aria-label': PropTypes__default["default"].string.isRequired,
/**
* Provide child elements to be rendered inside `ContentTabs`.
* These elements should render a `ContentTab`
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to the container node
*/
className: PropTypes__default["default"].string,
/**
* Specify whether component is contained type
*/
contained: PropTypes__default["default"].bool,
/**
* Used for tabs within a grid, this makes it so tabs span the full container width and have the same width. Only available on contained tabs with <9 children
*/
fullWidth: PropTypes__default["default"].bool,
/**
* If using `IconTab`, specify the size of the icon being used.
*/
iconSize: PropTypes__default["default"].oneOf(['default', 'lg']),
/**
* Provide the props that describe the left overflow button
*/
leftOverflowButtonProps: PropTypes__default["default"].object,
/**
* Specify whether to use the light component variant
*/
light: deprecate["default"](PropTypes__default["default"].bool, 'The `light` prop for `TabList` has ' + 'been deprecated in favor of the new `Layer` component. It will be removed in the next major release.'),
/**
* Provide the props that describe the right overflow button
*/
rightOverflowButtonProps: PropTypes__default["default"].object,
/**
* Optionally provide a delay (in milliseconds) passed to the lodash
* debounce of the onScroll handler. This will impact the responsiveness
* of scroll arrow buttons rendering when scrolling to the first or last tab.
*/
scrollDebounceWait: PropTypes__default["default"].number,
/**
* Choose whether to automatically scroll
* to newly selected tabs on component rerender
*/
scrollIntoView: PropTypes__default["default"].bool
};
/**
* Helper function to set up the behavior when a button is "long pressed".
* This function will take a ref to the tablist, a direction, and a setter
* for scrollLeft and will update the scroll position within a requestAnimationFrame.
*
* It returns a cleanup function to be run
* when the long press is deactivated
*/
function createLongPressBehavior(ref, direction, setScrollLeft) {
const node = ref.current;
if (!node) {
return () => {};
}
// We manually override the scroll behavior to be "auto".
// If it is set as smooth, this animation does not update correctly
const defaultScrollBehavior = node?.style['scroll-behavior'];
node.style['scroll-behavior'] = 'auto';
const scrollDelta = direction === 'forward' ? 5 : -5;
let frameId = null;
function tick() {
if (!node) {
return;
}
node.scrollLeft = node.scrollLeft + scrollDelta;
frameId = requestAnimationFrame(tick);
}
frameId = requestAnimationFrame(tick);
return () => {
// Restore the previous scroll behavior
node.style['scroll-behavior'] = defaultScrollBehavior;
// Make sure that our `scrollLeft` value is in sync with the existing
// `ref` after our requestAnimationFrame loop above
setScrollLeft(node.scrollLeft);
if (frameId) {
cancelAnimationFrame(frameId);
}
};
}
/**
* Tab
*/
const Tab = /*#__PURE__*/React.forwardRef(function Tab(_ref5, forwardRef) {
let {
as = 'button',
children,
className: customClassName,
disabled,
onClick,
onKeyDown,
secondaryLabel,
renderIcon: Icon,
labelOnly,
...rest
} = _ref5;
const prefix = usePrefix.usePrefix();
const {
selectedIndex,
setSelectedIndex,
baseId,
dismissable,
onTabCloseRequest
} = React__default["default"].useContext(TabsContext);
const {
index,
hasSecondaryLabel,
contained
} = React__default["default"].useContext(TabContext);
const dismissIconRef = React.useRef(null);
const tabRef = React.useRef(null);
const ref = useMergedRefs.useMergedRefs([forwardRef, tabRef]);
const [ignoreHover, setIgnoreHover] = React.useState(false);
const id = `${baseId}-tab-${index}`;
const panelId = `${baseId}-tabpanel-${index}`;
const className = cx__default["default"](`${prefix}--tabs__nav-item`, `${prefix}--tabs__nav-link`, {
[`${prefix}--tabs__nav-item--selected`]: selectedIndex === index,
[`${prefix}--tabs__nav-item--disabled`]: disabled,
[`${prefix}--tabs__nav-item--hover-off`]: ignoreHover,
'msk-tabs--tab-label-only': labelOnly
}, customClassName);
const BaseComponent = as;
const onDismissIconMouseEnter = evt => {
if (contained && tabRef.current) {
evt.stopPropagation();
setIgnoreHover(true);
tabRef.current.classList.add(`${prefix}--tabs__nav-item--hover-off`);
}
};
const onDismissIconMouseLeave = () => {
if (contained && tabRef.current) {
tabRef.current.classList.remove(`${prefix}--tabs__nav-item--hover-off`);
setIgnoreHover(false);
}
};
useEvent.useEvent(dismissIconRef, 'mouseover', onDismissIconMouseEnter);
useEvent.useEvent(dismissIconRef, 'mouseleave', onDismissIconMouseLeave);
const handleClose = evt => {
evt.stopPropagation();
onTabCloseRequest?.(index);
};
const handleKeyDown = event => {
if (dismissable && match.match(event, keys.Delete)) {
handleClose(event);
}
onKeyDown?.(event);
};
const DismissIcon =
/*#__PURE__*/
// eslint-disable-next-line jsx-a11y/click-events-have-key-events
React__default["default"].createElement("div", {
role: "button",
tabIndex: -1,
"aria-hidden": true,
className: cx__default["default"](`${prefix}--tabs__nav-item--close-icon`, {
[`${prefix}--visually-hidden`]: !dismissable
}),
onClick: handleClose,
"aria-label": "Close tab",
title: "Close tab",
ref: dismissIconRef
}, _Close || (_Close = /*#__PURE__*/React__default["default"].createElement(iconsReact.Close, null)));
const hasIcon = Icon ?? dismissable;
if (labelOnly) {
return /*#__PURE__*/React__default["default"].createElement("button", {
type: "button"
// eslint-disable-next-line jsx-a11y/no-interactive-element-to-noninteractive-role
,
role: "alert",
className: className,
title: secondaryLabel,
tabIndex: -1
}, /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--tabs__nav-item-label-wrapper`
}, /*#__PURE__*/React__default["default"].createElement("span", {
className: `${prefix}--tabs__nav-item-label`
}, children), /*#__PURE__*/React__default["default"].createElement("div", {
className: cx__default["default"](`${prefix}--tabs__nav-item--icon`, {
[`${prefix}--visually-hidden`]: !hasIcon
})
}, !dismissable && Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
size: 16
}))));
}
return /*#__PURE__*/React__default["default"].createElement(BaseComponent, _rollupPluginBabelHelpers["extends"]({}, rest, {
"aria-controls": panelId,
"aria-disabled": disabled,
"aria-selected": selectedIndex === index,
ref: ref,
id: id,
role: "tab",
className: className,
disabled: disabled,
onClick: evt => {
if (disabled) {
return;
}
setSelectedIndex(index);
onClick?.(evt);
},
onKeyDown: handleKeyDown,
tabIndex: selectedIndex === index ? '0' : '-1',
type: "button"
}), /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--tabs__nav-item-label-wrapper`
}, dismissable && Icon && /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--tabs__nav-item--icon-left`
}, /*#__PURE__*/React__default["default"].createElement(Icon, {
size: 16
})), /*#__PURE__*/React__default["default"].createElement("span", {
className: `${prefix}--tabs__nav-item-label`,
title: children
}, children), /*#__PURE__*/React__default["default"].createElement("div", {
className: cx__default["default"](`${prefix}--tabs__nav-item--icon`, {
[`${prefix}--visually-hidden`]: !hasIcon
})
}, DismissIcon, !dismissable && Icon && /*#__PURE__*/React__default["default"].createElement(Icon, {
size: 16
}))), hasSecondaryLabel && /*#__PURE__*/React__default["default"].createElement("div", {
className: `${prefix}--tabs__nav-item-secondary-label`,
title: secondaryLabel
}, secondaryLabel));
});
Tab.propTypes = {
/**
* Provide a custom element to render instead of the default button
*/
// @ts-expect-error: Invalid prop type derivation
as: PropTypes__default["default"].oneOfType([PropTypes__default["default"].string, PropTypes__default["default"].elementType]),
/**
* Provide child elements to be rendered inside `Tab`.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your Tab
*/
className: PropTypes__default["default"].string,
/**
* Whether your Tab is disabled.
*/
disabled: PropTypes__default["default"].bool,
/**
* Whether your Tab is only a label.
*/
labelOnly: PropTypes__default["default"].bool,
/**
* Provide a handler that is invoked when a user clicks on the control
*/
onClick: PropTypes__default["default"].func,
/**
* Provide a handler that is invoked on the key down event for the control
*/
onKeyDown: PropTypes__default["default"].func,
/*
* An optional parameter to allow overriding the anchor rendering.
* Useful for using Tab along with react-router or other client
* side router libraries.
**/
renderButton: PropTypes__default["default"].func,
/**
* Optional prop to render an icon next to the label.
* Can be a React component class
*/
// @ts-expect-error: Invalid prop type derivation
renderIcon: PropTypes__default["default"].oneOfType([PropTypes__default["default"].func, PropTypes__default["default"].object]),
/*
* An optional label to render under the primary tab label.
/* This prop is only useful for conained tabs
**/
secondaryLabel: PropTypes__default["default"].string
};
/**
* IconTab
*/
const IconTab = /*#__PURE__*/React__default["default"].forwardRef(function IconTab(_ref6, ref) {
let {
children,
className: customClassName,
defaultOpen = false,
enterDelayMs,
leaveDelayMs,
label,
...rest
} = _ref6;
const prefix = usePrefix.usePrefix();
const classNames = cx__default["default"](`${prefix}--tabs__nav-item--icon-only`, customClassName);
return /*#__PURE__*/React__default["default"].createElement(Tooltip.Tooltip, {
align: "bottom",
defaultOpen: defaultOpen,
className: `${prefix}--icon-tooltip`,
enterDelayMs: enterDelayMs,
label: label,
leaveDelayMs: leaveDelayMs
}, /*#__PURE__*/React__default["default"].createElement(Tab, _rollupPluginBabelHelpers["extends"]({
className: classNames,
ref: ref
}, rest), children));
});
IconTab.propTypes = {
/**
* Provide an icon to be rendered inside `IconTab` as the visual label for Tab.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to your Tab
*/
className: PropTypes__default["default"].string,
/**
* Specify whether the tooltip for the icon should be open when it first renders
*/
defaultOpen: PropTypes__default["default"].bool,
/**
* Specify the duration in milliseconds to delay before displaying the tooltip for the icon.
*/
enterDelayMs: PropTypes__default["default"].number,
/**
* Provide the label to be rendered inside the Tooltip. The label will use
* `aria-labelledby` and will fully describe the child node that is provided.
* This means that if you have text in the child node it will not be
* announced to the screen reader.
*/
label: PropTypes__default["default"].node.isRequired,
/**
* Specify the duration in milliseconds to delay before hiding the tooltip
*/
leaveDelayMs: PropTypes__default["default"].number
};
/**
* TabPanel
*/
const TabPanel = /*#__PURE__*/React__default["default"].forwardRef(function TabPanel(_ref7, forwardRef) {
let {
children,
className: customClassName,
...rest
} = _ref7;
const prefix = usePrefix.usePrefix();
const panel = React.useRef(null);
const ref = useMergedRefs.useMergedRefs([forwardRef, panel]);
const [tabIndex, setTabIndex] = React.useState(0);
const [interactiveContent, setInteractiveContent] = React.useState(false);
const {
selectedIndex,
baseId
} = React__default["default"].useContext(TabsContext);
const index = React__default["default"].useContext(TabPanelContext);
const id = `${baseId}-tabpanel-${index}`;
const tabId = `${baseId}-tab-${index}`;
const className = cx__default["default"](`${prefix}--tab-content`, customClassName, {
[`${prefix}--tab-content--interactive`]: interactiveContent
});
useEffectOnce.useEffectOnce(() => {
if (!panel.current) {
return;
}
const content = useNoInteractiveChildren.getInteractiveContent(panel.current);
if (content) {
setInteractiveContent(true);
setTabIndex(-1);
}
});
// tabindex should only be 0 if no interactive content in children
React.useEffect(() => {
const node = panel.current;
if (!node) {
return;
}
function callback() {
const content = useNoInteractiveChildren.getInteractiveContent(node);
if (content) {
setInteractiveContent(true);
setTabIndex(-1);
} else {
setInteractiveContent(false);
setTabIndex(0);
}
}
const observer = new MutationObserver(callback);
observer.observe(node, {
childList: true,
subtree: true
});
return () => observer.disconnect();
}, []);
return /*#__PURE__*/React__default["default"].createElement("div", _rollupPluginBabelHelpers["extends"]({}, rest, {
"aria-labelledby": tabId,
id: id,
className: className,
ref: ref,
role: "tabpanel",
tabIndex: tabIndex,
hidden: selectedIndex !== index
}), children);
});
TabPanel.propTypes = {
/**
* Provide child elements to be rendered inside `TabPanel`.
*/
children: PropTypes__default["default"].node,
/**
* Specify an optional className to be added to TabPanel.
*/
className: PropTypes__default["default"].string
};
/**
* TabPanels
*/
function TabPanels(_ref8) {
let {
children
} = _ref8;
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, React__default["default"].Children.map(children, (child, index) => {
return /*#__PURE__*/React__default["default"].createElement(TabPanelContext.Provider, {
value: index
}, child);
}));
}
TabPanels.propTypes = {
/**
* Provide child elements to be rendered inside `TabPanels`.
*/
children: PropTypes__default["default"].node
};
exports.IconTab = IconTab;
exports.Tab = Tab;
exports.TabList = TabList;
exports.TabPanel = TabPanel;
exports.TabPanels = TabPanels;
exports.Tabs = Tabs;