@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
132 lines (131 loc) • 6.03 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import * as React from 'react';
import { useRef } from 'react';
import join from '../utils/join';
import useProperty from '../utils/useProperty';
import { Box, Flex } from '../Flex';
import { twMerge } from '../../twMerge';
import { cn } from '../../lib/utils';
const TabContext = React.createContext({
selectedIndex: 0,
tabCount: 0,
setSelectedIndex: (index) => { },
});
const isTab = (c) => {
return c.type === Tab || SupportedTabMenuComps.has(c.type);
};
const isTabContent = (c) => {
return c.type === Content || SupportedTabContentComps.has(c.type);
};
export const Tabs = (props) => {
const { autoFocus, children, onValueChange: _onValueChange, defaultValue: _defaultValue, value: _value, keyboardNavigation = true, selectedIndex: _selectedIndex, defaultSelectedIndex: _defaultSelectedIndex, onSelectedIndexChange: _onSelectedIndexChange, ...boxProps } = props;
let [selectedIndex, doSetSelectedIndex] = useProperty(props, 'selectedIndex', 0);
const [selectedValue, setSelectedValue] = useProperty(props, 'value', 0);
const allChildren = React.Children.toArray(children);
const values = [];
const tabs = allChildren.filter(isTab).map((tab, index) => {
values.push(tab.props.value);
return React.cloneElement(tab, {
index,
keyboardNavigation,
autoFocus,
});
});
const contents = allChildren.filter(isTabContent);
const contentValues = contents.map((c) => c.props.value);
const shouldUseValue = (props.value !== undefined || props.defaultValue !== undefined) &&
props.selectedIndex === undefined &&
props.defaultSelectedIndex === undefined;
if (shouldUseValue) {
const indexOfValue = values.indexOf(selectedValue);
if (indexOfValue > -1) {
selectedIndex = indexOfValue;
}
const reorderContents = contentValues.filter((contentValue) => values.indexOf(contentValue) != -1).length ===
tabs.length;
if (reorderContents) {
contents.sort((c1, c2) => {
const v1 = c1.props.value;
const v2 = c2.props.value;
return values.indexOf(v1) - values.indexOf(v2);
});
}
}
const setSelectedIndex = (index) => {
if (shouldUseValue) {
const selectedValue = values[index];
setSelectedValue(selectedValue);
}
doSetSelectedIndex(index);
};
const currentContent = contents[selectedIndex];
const { value, ...contentProps } = (currentContent?.props || {});
const fillerClassName = cn('ab-Tabs__Filler', 'twa:bg-(--ab-cmp-tabs-strip__background)');
return (_jsx(TabContext.Provider, { value: {
selectedIndex,
tabCount: tabs.length,
setSelectedIndex,
}, children: _jsxs(Box, { ...boxProps, className: join(boxProps.className, 'ab-Tabs twa:flex twa:flex-col'), "data-selected-index": selectedIndex, children: [_jsxs(Flex, { flexDirection: "row", className: cn('ab-Tabs__Strip', 'twa:bg-(--ab-cmp-tabs-strip__background)', 'twa:pt-0.5'), children: [_jsx(Box, { className: fillerClassName }), tabs, _jsx(Flex, { className: cn(fillerClassName, 'twa:flex-1') })] }), _jsx(Box, { ...contentProps, className: `ab-Tabs__Body twa:p-2 twa:flex-1 ${contentProps.className || ''} `, children: currentContent })] }) }));
};
export const Tab = (props) => {
const { index, autoFocus, keyboardNavigation = true, className: propsClassName, ...boxProps } = props;
const context = React.useContext(TabContext);
const baseClassName = 'ab-Tabs__Tab';
const active = context.selectedIndex === props.index;
const beforeActive = context.selectedIndex === props.index + 1;
const className = cn(baseClassName, active ? `${baseClassName}--active` : '', beforeActive ? `${baseClassName}--before-active` : '', 'twa:cursor-pointer twa:p-2', propsClassName);
const ref = useRef(null);
React.useEffect(() => {
if (active && autoFocus && keyboardNavigation) {
ref.current?.focus();
}
}, [active, autoFocus]);
const mountedRef = React.useRef(false);
React.useEffect(() => {
if (!mountedRef.current) {
return;
}
if (active && keyboardNavigation) {
ref.current?.focus();
}
}, [active, keyboardNavigation]);
React.useEffect(() => {
mountedRef.current = true;
}, []);
return (_jsx(Box, { ref: ref, tabIndex: active ? 0 : -1, ...boxProps, className: twMerge('twa:p-2', className), onClick: (event) => {
context.setSelectedIndex(props.index);
props.onClick?.(event);
}, onKeyDown: (event) => {
if (keyboardNavigation) {
if (event.key === 'Enter') {
context.setSelectedIndex(props.index);
}
if (event.key === 'ArrowLeft') {
event.preventDefault();
let nextIndex = props.index - 1;
if (nextIndex < 0) {
nextIndex = context.tabCount - 1;
}
context.setSelectedIndex(nextIndex);
}
if (event.key === 'ArrowRight') {
event.preventDefault();
let nextIndex = props.index + 1;
if (nextIndex > context.tabCount - 1) {
nextIndex = 0;
}
context.setSelectedIndex(nextIndex);
}
}
props.onKeyDown?.(event);
} }));
};
export const SupportedTabMenuComps = new Set();
SupportedTabMenuComps.add(Tab);
export const Content = (props) => {
return _jsx(_Fragment, { children: props.children });
};
export const SupportedTabContentComps = new Set();
SupportedTabContentComps.add(Content);
Tabs.Tab = Tab;
Tabs.Content = Content;