flowbite-react
Version:
Official React components built for Flowbite and Tailwind CSS
117 lines (114 loc) • 4.1 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import { forwardRef, useId, useMemo, Children, useRef, useState, useEffect, useImperativeHandle } from 'react';
import { twMerge } from 'tailwind-merge';
import { mergeDeep } from '../../helpers/merge-deep.mjs';
import { getTheme } from '../../theme-store/index.mjs';
import { TabItem } from './TabItem.mjs';
const TabsComponent = forwardRef(
({ children, className, onActiveTabChange, style = "default", theme: customTheme = {}, ...props }, ref) => {
const theme = mergeDeep(getTheme().tabs, customTheme);
const id = useId();
const tabs = useMemo(
() => Children.map(
Children.toArray(children),
({ props: props2 }) => props2
),
[children]
);
const tabRefs = useRef([]);
const [activeTab, setActiveTab] = useState(
Math.max(
0,
tabs.findIndex((tab) => tab.active)
)
);
const [focusedTab, setFocusedTab] = useState(-1);
const setActiveTabWithCallback = (activeTab2) => {
setActiveTab(activeTab2);
if (onActiveTabChange)
onActiveTabChange(activeTab2);
};
const handleClick = ({ target }) => {
setActiveTabWithCallback(target);
setFocusedTab(target);
};
const handleKeyboard = ({ event, target }) => {
if (event.key === "ArrowLeft") {
setFocusedTab(Math.max(0, focusedTab - 1));
}
if (event.key === "ArrowRight") {
setFocusedTab(Math.min(tabs.length - 1, focusedTab + 1));
}
if (event.key === "Enter") {
setActiveTabWithCallback(target);
setFocusedTab(target);
}
};
const tabItemStyle = theme.tablist.tabitem.styles[style];
const tabItemContainerStyle = theme.tabitemcontainer.styles[style];
useEffect(() => {
tabRefs.current[focusedTab]?.focus();
}, [focusedTab]);
useImperativeHandle(ref, () => ({
setActiveTab: setActiveTabWithCallback
}));
return /* @__PURE__ */ jsxs("div", { className: twMerge(theme.base, className), children: [
/* @__PURE__ */ jsx(
"div",
{
"aria-label": "Tabs",
role: "tablist",
className: twMerge(theme.tablist.base, theme.tablist.styles[style], className),
...props,
children: tabs.map((tab, index) => /* @__PURE__ */ jsxs(
"button",
{
type: "button",
"aria-controls": `${id}-tabpanel-${index}`,
"aria-selected": index === activeTab,
className: twMerge(
theme.tablist.tabitem.base,
tabItemStyle.base,
index === activeTab && tabItemStyle.active.on,
index !== activeTab && !tab.disabled && tabItemStyle.active.off
),
disabled: tab.disabled,
id: `${id}-tab-${index}`,
onClick: () => handleClick({ target: index }),
onKeyDown: (event) => handleKeyboard({ event, target: index }),
ref: (element) => tabRefs.current[index] = element,
role: "tab",
tabIndex: index === focusedTab ? 0 : -1,
style: { zIndex: index === focusedTab ? 2 : 1 },
children: [
tab.icon && /* @__PURE__ */ jsx(tab.icon, { className: theme.tablist.tabitem.icon }),
tab.title
]
},
index
))
}
),
/* @__PURE__ */ jsx("div", { className: twMerge(theme.tabitemcontainer.base, tabItemContainerStyle), children: tabs.map((tab, index) => /* @__PURE__ */ jsx(
"div",
{
"aria-labelledby": `${id}-tab-${index}`,
className: theme.tabpanel,
hidden: index !== activeTab,
id: `${id}-tabpanel-${index}`,
role: "tabpanel",
tabIndex: 0,
children: tab.children
},
index
)) })
] });
}
);
TabsComponent.displayName = "Tabs";
const Tabs = Object.assign(TabsComponent, {
Item: TabItem
});
export { Tabs };
//# sourceMappingURL=Tabs.mjs.map