diff --git a/src/Tabs/TabPanel.tsx b/src/Tabs/TabPanel.tsx index 47517d54..34fec346 100644 --- a/src/Tabs/TabPanel.tsx +++ b/src/Tabs/TabPanel.tsx @@ -10,13 +10,14 @@ export function TabPanel(props: TabPanelProps) { context.registerTab({ id: props.id, title: props.title, + order: props.order, }); return () => { context.unregisterTab(props.id); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.id, props.title]); + }, [props.id, props.title, props.order]); return (
` `} `; +function sortedByOrder(tabs: Array): Array { + return [...tabs].sort((tab, other) => (tab.order ?? 0) - (other.order ?? 0)); +} + export function TabsHeader() { const context = useContext(TabsContext); return ( - {context.tabs.map((tab: TabPanelProps) => { + {sortedByOrder(context.tabs).map((tab: TabPanelProps) => { const isActiveTab = context.activeTabID === tab.id; return ( diff --git a/src/Tabs/index.test.tsx b/src/Tabs/index.test.tsx index 1bf744f5..5952dfbf 100644 --- a/src/Tabs/index.test.tsx +++ b/src/Tabs/index.test.tsx @@ -50,6 +50,27 @@ describe('Tabs', () => { expect(tabContent2).toBeVisible(); }); + it('shows tabs in ascending order, no matter when they mount', () => { + const { rerender } = render( + + + + , + ); + + rerender( + + + + + , + ); + + expect( + screen.getAllByRole('listitem').map((title) => title.textContent), + ).toEqual(['first', 'second', 'third']); + }); + it('set active tab to last tabID', () => { const title1 = 'My tab title1'; const content1 = 'My tab content1'; diff --git a/src/Tabs/types.ts b/src/Tabs/types.ts index 8947ccdf..54b28d7f 100644 --- a/src/Tabs/types.ts +++ b/src/Tabs/types.ts @@ -11,5 +11,9 @@ export type TabsProps = { export type TabPanelProps = { id: TTabID; title: ReactNode; + + /** Ascending, panels sharing an order keep the order they mounted in. */ + order?: number; + children?: ReactNode; };