UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

499 lines (498 loc) 14.2 kB
'use strict'; 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'; } } }, []);