@itwin/itwinui-react
Version:
A react component library for iTwinUI
499 lines (498 loc) • 14.2 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true,
});
function _export(target, all) {
for (var name in all)
Object.defineProperty(target, name, {
enumerable: true,
get: all[name],
});
}
_export(exports, {
Tab: function () {
return LegacyTab;
},
Tabs: function () {
return Tabs;
},
unstable_TabsPresentation: function () {
return unstable_TabsPresentation;
},
});
const _interop_require_default = require('@swc/helpers/_/_interop_require_default');
const _interop_require_wildcard = require('@swc/helpers/_/_interop_require_wildcard');
const _classnames = /*#__PURE__*/ _interop_require_default._(
require('classnames'),
);
const _react = /*#__PURE__*/ _interop_require_wildcard._(require('react'));
const _index = require('../../utils/index.js');
const _Icon = require('../Icon/Icon.js');
const TabsWrapper = _react.forwardRef((props, ref) => {
let {
children,
orientation = 'horizontal',
type = 'default',
focusActivationMode = 'auto',
color = 'blue',
defaultValue,
value: activeValueProp,
onValueChange,
...rest
} = props;
let [activeValue, setActiveValue] = (0, _index.useControlledState)(
defaultValue,
activeValueProp,
onValueChange,
);
let [stripeProperties, setStripeProperties] = _react.useState({});
let [hasSublabel, setHasSublabel] = _react.useState(false);
let idPrefix = (0, _index.useId)();
return _react.createElement(
TabsWrapperPresentation,
{
...rest,
orientation: orientation,
style: {
...stripeProperties,
...props?.style,
},
ref: ref,
},
_react.createElement(
TabsContext.Provider,
{
value: {
orientation,
type,
activeValue,
setActiveValue,
setStripeProperties,
idPrefix,
focusActivationMode,
hasSublabel,
setHasSublabel,
color,
},
},
children,
),
);
});
if ('development' === process.env.NODE_ENV)
TabsWrapper.displayName = 'Tabs.Wrapper';
const TabsWrapperPresentation = _react.forwardRef((props, forwardedRef) => {
let { orientation = 'horizontal', ...rest } = props;
return _react.createElement(_index.Box, {
...rest,
className: (0, _classnames.default)(
'iui-tabs-wrapper',
`iui-${orientation}`,
props.className,
),
ref: forwardedRef,
});
});
const TabList = _react.forwardRef((props, ref) => {
let { className, children, ...rest } = props;
let { type, hasSublabel, color, orientation } = (0, _index.useSafeContext)(
TabsContext,
);
let isClient = (0, _index.useIsClient)();
let tablistRef = _react.useRef(null);
let [tablistSizeRef, tabsWidth] = (0, _index.useContainerWidth)(
'default' !== type,
);
let refs = (0, _index.useMergedRefs)(
ref,
tablistRef,
tablistSizeRef,
useScrollbarGutter(),
);
return _react.createElement(
TabListPresentation,
{
className: (0, _classnames.default)(
{
'iui-animated': 'default' !== type && isClient,
},
className,
),
'data-iui-orientation': orientation,
role: 'tablist',
ref: refs,
...rest,
type: type,
color: color,
size: hasSublabel ? 'large' : void 0,
orientation: orientation,
},
_react.createElement(
TabListContext.Provider,
{
value: {
tabsWidth,
tablistRef,
},
},
children,
),
);
});
if ('development' === process.env.NODE_ENV)
TabList.displayName = 'Tabs.TabList';
const TabListPresentation = _react.forwardRef((props, forwardedRef) => {
let {
type = 'default',
color,
size,
orientation = 'horizontal',
...rest
} = props;
return _react.createElement(_index.Box, {
...rest,
className: (0, _classnames.default)(
'iui-tabs',
`iui-${type}`,
{
'iui-green': 'green' === color,
'iui-large': 'large' === size,
},
props.className,
),
'data-iui-orientation': orientation,
ref: forwardedRef,
});
});
const Tab = _react.forwardRef((props, forwardedRef) => {
let { children, value, label, ...rest } = props;
let {
orientation,
activeValue,
setActiveValue,
type,
setStripeProperties,
idPrefix,
focusActivationMode,
} = (0, _index.useSafeContext)(TabsContext);
let { tabsWidth, tablistRef } = (0, _index.useSafeContext)(TabListContext);
let tabRef = _react.useRef(void 0);
let isActive = activeValue === value;
let isActiveRef = (0, _index.useLatestRef)(isActive);
(0, _index.useLayoutEffect)(() => {
if (isActiveRef.current)
tabRef.current?.parentElement?.scrollTo({
['horizontal' === orientation ? 'left' : 'top']:
tabRef.current?.[
'horizontal' === orientation ? 'offsetLeft' : 'offsetTop'
] - 4,
behavior: 'instant',
});
}, [isActiveRef, orientation]);
(0, _index.useLayoutEffect)(() => {
let updateStripe = () => {
let currentTabRect = tabRef.current?.getBoundingClientRect();
let tabslistRect = tablistRef.current?.getBoundingClientRect();
let currentTabLeftIncludingScroll =
(currentTabRect?.x ?? 0) + (tablistRef.current?.scrollLeft ?? 0);
let tabsStripePosition =
null != currentTabRect && null != tabslistRect
? {
horizontal: currentTabLeftIncludingScroll - tabslistRect.x,
vertical: currentTabRect.y - tabslistRect.y,
}
: {
horizontal: 0,
vertical: 0,
};
setStripeProperties({
'--iui-tabs-stripe-size':
'horizontal' === orientation
? `${currentTabRect?.width}px`
: `${currentTabRect?.height}px`,
'--iui-tabs-stripe-position':
'horizontal' === orientation
? `${tabsStripePosition.horizontal}px`
: `${tabsStripePosition.vertical}px`,
});
};
if ('default' !== type && isActive) updateStripe();
}, [
type,
orientation,
isActive,
tabsWidth,
setStripeProperties,
tablistRef,
value,
]);
let onKeyDown = (event) => {
if (event.altKey) return;
let allTabs = Array.from(event.currentTarget.parentElement?.children ?? []);
let nextTab = tabRef.current?.nextElementSibling ?? allTabs.at(0);
let previousTab = tabRef.current?.previousElementSibling ?? allTabs.at(-1);
switch (event.key) {
case 'ArrowDown':
if ('vertical' === orientation) {
nextTab?.focus();
event.preventDefault();
}
break;
case 'ArrowRight':
if ('horizontal' === orientation) {
nextTab?.focus();
event.preventDefault();
}
break;
case 'ArrowUp':
if ('vertical' === orientation) {
previousTab?.focus();
event.preventDefault();
}
break;
case 'ArrowLeft':
if ('horizontal' === orientation) {
previousTab?.focus();
event.preventDefault();
}
break;
default:
break;
}
};
let setInitialActiveRef = _react.useCallback(
(element) => {
if (void 0 !== activeValue) return;
if (element?.matches(':first-of-type')) setActiveValue(value);
},
[activeValue, setActiveValue, value],
);
return _react.createElement(
TabPresentation,
{
as: _index.ButtonBase,
role: 'tab',
tabIndex: isActive ? 0 : -1,
'aria-selected': isActive,
'aria-controls': `${idPrefix}-panel-${value.replaceAll(' ', '-')}`,
ref: (0, _index.useMergedRefs)(tabRef, forwardedRef, setInitialActiveRef),
...rest,
id: `${idPrefix}-tab-${value.replaceAll(' ', '-')}`,
onClick: (0, _index.mergeEventHandlers)(props.onClick, () =>
setActiveValue(value),
),
onKeyDown: (0, _index.mergeEventHandlers)(props.onKeyDown, onKeyDown),
onFocus: (0, _index.mergeEventHandlers)(props.onFocus, () => {
tabRef.current?.scrollIntoView({
block: 'nearest',
inline: 'nearest',
});
if ('auto' === focusActivationMode && !props.disabled)
setActiveValue(value);
}),
},
label ? _react.createElement(Tabs.TabLabel, null, label) : children,
);
});
if ('development' === process.env.NODE_ENV) Tab.displayName = 'Tabs.Tab';
const TabPresentation = _react.forwardRef((props, forwardedRef) =>
_react.createElement(_index.Box, {
as: 'button',
...props,
className: (0, _classnames.default)('iui-tab', props.className),
ref: forwardedRef,
}),
);
const TabIcon = _react.forwardRef((props, ref) =>
_react.createElement(_Icon.Icon, {
...props,
className: (0, _classnames.default)('iui-tab-icon', props?.className),
ref: ref,
}),
);
if ('development' === process.env.NODE_ENV)
TabIcon.displayName = 'Tabs.TabIcon';
const TabLabel = _index.polymorphic.span('iui-tab-label');
if ('development' === process.env.NODE_ENV)
TabLabel.displayName = 'Tabs.TabLabel';
const TabDescription = _react.forwardRef((props, ref) => {
let { className, children, ...rest } = props;
let { hasSublabel, setHasSublabel } = (0, _index.useSafeContext)(TabsContext);
(0, _index.useLayoutEffect)(() => {
if (!hasSublabel) setHasSublabel(true);
}, [hasSublabel, setHasSublabel]);
return _react.createElement(
_index.Box,
{
as: 'span',
className: (0, _classnames.default)('iui-tab-description', className),
ref: ref,
...rest,
},
children,
);
});
if ('development' === process.env.NODE_ENV)
TabDescription.displayName = 'Tabs.TabDescription';
const TabsActions = _react.forwardRef((props, ref) => {
let { wrapperProps, className, children, ...rest } = props;
return _react.createElement(
_index.Box,
{
...wrapperProps,
className: (0, _classnames.default)(
'iui-tabs-actions-wrapper',
wrapperProps?.className,
),
},
_react.createElement(
_index.Box,
{
className: (0, _classnames.default)('iui-tabs-actions', className),
ref: ref,
...rest,
},
children,
),
);
});
if ('development' === process.env.NODE_ENV)
TabsActions.displayName = 'Tabs.Actions';
const TabsPanel = _react.forwardRef((props, ref) => {
let { value, className, children, ...rest } = props;
let { activeValue, idPrefix } = (0, _index.useSafeContext)(TabsContext);
return _react.createElement(
_index.Box,
{
className: (0, _classnames.default)('iui-tabs-content', className),
'aria-labelledby': `${idPrefix}-tab-${value.replaceAll(' ', '-')}`,
role: 'tabpanel',
hidden: activeValue !== value ? true : void 0,
ref: ref,
...rest,
id: `${idPrefix}-panel-${value.replaceAll(' ', '-')}`,
},
children,
);
});
if ('development' === process.env.NODE_ENV)
TabsPanel.displayName = 'Tabs.Panel';
const LegacyTabsComponent = _react.forwardRef((props, forwardedRef) => {
let actions;
if ('pill' !== props.type && props.actions) {
actions = props.actions;
props = {
...props,
};
delete props.actions;
}
let {
labels,
onTabSelected,
focusActivationMode,
color,
activeIndex: activeIndexProp,
tabsClassName,
contentClassName,
wrapperClassName,
children,
...rest
} = props;
let [activeIndex, setActiveIndex] = (0, _index.useControlledState)(
0,
activeIndexProp,
onTabSelected,
);
return _react.createElement(
TabsWrapper,
{
className: wrapperClassName,
focusActivationMode: focusActivationMode,
color: color,
value: `${activeIndex}`,
onValueChange: (value) => setActiveIndex(Number(value)),
...rest,
},
_react.createElement(
TabList,
{
className: tabsClassName,
ref: forwardedRef,
},
labels.map((label, index) => {
let tabValue = `${index}`;
return _react.isValidElement(label)
? _react.cloneElement(label, {
value: tabValue,
})
: _react.createElement(LegacyTab, {
key: index,
value: tabValue,
label: label,
});
}),
),
actions && _react.createElement(TabsActions, null, actions),
children &&
_react.createElement(
TabsPanel,
{
value: `${activeIndex}`,
className: contentClassName,
},
children,
),
);
});
if ('development' === process.env.NODE_ENV)
LegacyTabsComponent.displayName = 'Tabs';
const LegacyTab = _react.forwardRef((props, forwardedRef) => {
let { label, sublabel, startIcon, children, value, ...rest } = props;
return _react.createElement(
_react.Fragment,
null,
_react.createElement(
Tab,
{
...rest,
value: value,
ref: forwardedRef,
},
startIcon && _react.createElement(TabIcon, null, startIcon),
_react.createElement(TabLabel, null, label),
sublabel && _react.createElement(TabDescription, null, sublabel),
children,
),
);
});
const Tabs = Object.assign(LegacyTabsComponent, {
Wrapper: TabsWrapper,
TabList: TabList,
Tab: Tab,
TabIcon: TabIcon,
TabLabel: TabLabel,
TabDescription: TabDescription,
Actions: TabsActions,
Panel: TabsPanel,
});
const unstable_TabsPresentation = {
Wrapper: TabsWrapperPresentation,
TabList: TabListPresentation,
Tab: TabPresentation,
};
const TabsContext = _react.createContext(void 0);
if ('development' === process.env.NODE_ENV)
TabsContext.displayName = 'TabsContext';
const TabListContext = _react.createContext(void 0);
if ('development' === process.env.NODE_ENV)
TabListContext.displayName = 'TabListContext';
const useScrollbarGutter = () =>
_react.useCallback((element) => {
if (element) {
if (element.scrollHeight > element.clientHeight) {
element.style.scrollbarGutter = 'stable';
if (!CSS.supports('scrollbar-gutter: stable'))
element.style.overflowY = 'scroll';
}
}
}, []);