Shared: Components: Tabs: Added multiple mode for the component.
This commit is contained in:
parent
d2d7d535d1
commit
24d7b695ab
@ -31,9 +31,14 @@ import { TabsTypes } from "./Tabs.enums";
|
||||
|
||||
export const StyledTabs = styled.div<{
|
||||
stickyTop?: string;
|
||||
multiple: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
${(props) =>
|
||||
props.multiple &&
|
||||
css`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`};
|
||||
|
||||
.sticky {
|
||||
height: 33px;
|
||||
@ -128,6 +133,7 @@ export const ScrollbarTabs = styled(Scrollbar)<{
|
||||
|
||||
export const TabList = styled.div<{
|
||||
$type?: TabsTypes;
|
||||
multiple: boolean;
|
||||
}>`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -136,6 +142,13 @@ export const TabList = styled.div<{
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
|
||||
${(props) =>
|
||||
props.multiple &&
|
||||
css`
|
||||
flex-wrap: wrap;
|
||||
height: fit-content;
|
||||
`};
|
||||
|
||||
gap: ${(props) => (props.$type === TabsTypes.Primary ? "20px" : "8px")};
|
||||
|
||||
border-bottom: ${(props) =>
|
||||
|
@ -39,26 +39,26 @@ import {
|
||||
} from "./Tabs.styled";
|
||||
import { TabsProps, TTabItem } from "./Tabs.types";
|
||||
import { TabsTypes } from "./Tabs.enums";
|
||||
import { OFFSET_RIGHT, OFFSET_LEFT, INDEX_NOT_FOUND } from "./Tabs.constants";
|
||||
import { OFFSET_RIGHT, OFFSET_LEFT } from "./Tabs.constants";
|
||||
|
||||
const Tabs = (props: TabsProps) => {
|
||||
const {
|
||||
items,
|
||||
selectedItemId,
|
||||
selectedItems = [],
|
||||
type = TabsTypes.Primary,
|
||||
stickyTop,
|
||||
onSelect,
|
||||
multiple = false,
|
||||
...rest
|
||||
} = props;
|
||||
|
||||
let selectedItemIndex = items.findIndex((item) => item.id === selectedItemId);
|
||||
if (selectedItemIndex === INDEX_NOT_FOUND) {
|
||||
selectedItemIndex = 0;
|
||||
}
|
||||
const selectedItemIndex = !selectedItemId
|
||||
? 0
|
||||
: items.findIndex((item) => item.id === selectedItemId);
|
||||
|
||||
const [currentItem, setCurrentItem] = useState<TTabItem>(
|
||||
items[selectedItemIndex],
|
||||
);
|
||||
const [currentItem, setCurrentItem] = useState(selectedItemIndex);
|
||||
const [multipleItems, setMultipleItems] = useState(selectedItems);
|
||||
|
||||
const tabsRef = useRef<HTMLDivElement>(null);
|
||||
const scrollRef = useRef<ScrollbarType>(null);
|
||||
@ -67,8 +67,8 @@ const Tabs = (props: TabsProps) => {
|
||||
const isViewLastTab = useViewTab(scrollRef, tabsRef, items.length - 1);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentItem(items[selectedItemIndex]);
|
||||
}, [selectedItemIndex, items]);
|
||||
if (!multiple) setCurrentItem(selectedItemIndex);
|
||||
}, [selectedItemIndex, items, multiple]);
|
||||
|
||||
const scrollToTab = (index: number): void => {
|
||||
if (!scrollRef.current || !tabsRef.current) return;
|
||||
@ -95,43 +95,84 @@ const Tabs = (props: TabsProps) => {
|
||||
};
|
||||
|
||||
const setSelectedItem = (selectedTabItem: TTabItem, index: number): void => {
|
||||
setCurrentItem(selectedTabItem);
|
||||
scrollToTab(index);
|
||||
if (multiple) {
|
||||
const indexOperation = () => {
|
||||
const newArray = [...multipleItems];
|
||||
|
||||
const deletionIndex = newArray.indexOf(index);
|
||||
|
||||
if (deletionIndex !== -1) {
|
||||
newArray.splice(deletionIndex, 1);
|
||||
|
||||
return newArray;
|
||||
}
|
||||
|
||||
newArray.push(index);
|
||||
return newArray;
|
||||
};
|
||||
|
||||
const updatedActiveTab = indexOperation();
|
||||
|
||||
setMultipleItems(updatedActiveTab);
|
||||
onSelect?.(selectedTabItem);
|
||||
return;
|
||||
}
|
||||
|
||||
setCurrentItem(index);
|
||||
onSelect?.(selectedTabItem);
|
||||
|
||||
scrollToTab(index);
|
||||
};
|
||||
|
||||
const renderContent = (
|
||||
<TabList ref={tabsRef} $type={type} multiple={multiple}>
|
||||
{items.map((item, index) => {
|
||||
const isActive = multiple
|
||||
? multipleItems.indexOf(index) !== -1
|
||||
: index === currentItem;
|
||||
|
||||
return (
|
||||
<Tab
|
||||
key={item.id}
|
||||
isActive={isActive}
|
||||
isDisabled={item?.isDisabled}
|
||||
$type={type}
|
||||
onClick={() => {
|
||||
item.onClick?.();
|
||||
setSelectedItem(item, index);
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
<TabSubLine isActive={isActive} $type={type} />
|
||||
</Tab>
|
||||
);
|
||||
})}
|
||||
</TabList>
|
||||
);
|
||||
return (
|
||||
<StyledTabs {...rest} stickyTop={stickyTop}>
|
||||
<div className="sticky">
|
||||
{!isViewFirstTab && <div className="blur-ahead" />}
|
||||
<ScrollbarTabs ref={scrollRef} autoHide={false} noScrollY $type={type}>
|
||||
<TabList ref={tabsRef} $type={type}>
|
||||
{items.map((item, index) => {
|
||||
const isActive = item.id === currentItem.id;
|
||||
return (
|
||||
<Tab
|
||||
key={item.id}
|
||||
isActive={isActive}
|
||||
isDisabled={item?.isDisabled}
|
||||
$type={type}
|
||||
onClick={() => {
|
||||
item.onClick?.();
|
||||
setSelectedItem(item, index);
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
<TabSubLine isActive={isActive} $type={type} />
|
||||
</Tab>
|
||||
);
|
||||
})}
|
||||
</TabList>
|
||||
</ScrollbarTabs>
|
||||
{!isViewLastTab && <div className="blur-back" />}
|
||||
</div>
|
||||
<StyledTabs {...rest} stickyTop={stickyTop} multiple={multiple}>
|
||||
{multiple && renderContent}
|
||||
|
||||
{!multiple && (
|
||||
<div className="sticky">
|
||||
{!isViewFirstTab && <div className="blur-ahead" />}
|
||||
|
||||
<ScrollbarTabs
|
||||
ref={scrollRef}
|
||||
autoHide={false}
|
||||
noScrollY
|
||||
$type={type}
|
||||
>
|
||||
{renderContent}
|
||||
</ScrollbarTabs>
|
||||
|
||||
{!isViewLastTab && <div className="blur-back" />}
|
||||
</div>
|
||||
)}
|
||||
<div className="sticky-indent" />
|
||||
|
||||
<div className="tabs-body">{currentItem?.content}</div>
|
||||
{!multiple && (
|
||||
<div className="tabs-body">{items[currentItem]?.content}</div>
|
||||
)}
|
||||
</StyledTabs>
|
||||
);
|
||||
};
|
||||
|
@ -44,10 +44,13 @@ export interface TabsProps {
|
||||
items: TTabItem[];
|
||||
/** Selected item of tabs. */
|
||||
selectedItemId?: number | string;
|
||||
selectedItems?: number[];
|
||||
/** Theme for displaying tabs. */
|
||||
type?: TabsTypes;
|
||||
/** Tab indentation for sticky positioning. */
|
||||
stickyTop?: string;
|
||||
/** Enables multiple select */
|
||||
multiple?: boolean;
|
||||
/** Sets a callback function that is triggered when the tab is selected. */
|
||||
onSelect?: (element: TTabItem) => void;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user