File tree Expand file tree Collapse file tree 3 files changed +62
-0
lines changed
packages/components/src/navigation Expand file tree Collapse file tree 3 files changed +62
-0
lines changed Original file line number Diff line number Diff line change @@ -18,6 +18,13 @@ interface NavTabProps {
1818 index : number ;
1919 isDraggable : boolean ;
2020 contextActions ?: ResolvableContextAction | ResolvableContextAction [ ] ;
21+ /**
22+ * Optional render function to render content after the tab title.
23+ *
24+ * @param tab The tab to render content for
25+ * @returns The content to render after the tab title
26+ */
27+ renderAfterTabContent ?: ( tab : NavTabItem ) => React . ReactNode ;
2128}
2229
2330const NavTab = memo (
@@ -30,6 +37,7 @@ const NavTab = memo(
3037 index,
3138 isDraggable,
3239 contextActions,
40+ renderAfterTabContent,
3341 } : NavTabProps ) => {
3442 const { key, isClosable = onClose != null , title, icon } = tab ;
3543
@@ -98,6 +106,7 @@ const NavTab = memo(
98106 { title }
99107 < Tooltip > { title } </ Tooltip >
100108 </ span >
109+ { renderAfterTabContent ?.( tab ) }
101110 { isClosable && (
102111 < Button
103112 kind = "ghost"
Original file line number Diff line number Diff line change 1+ import React from 'react' ;
2+ import { render , screen } from '@testing-library/react' ;
3+ import userEvent from '@testing-library/user-event' ;
4+ import NavTabList , { type NavTabItem } from './NavTabList' ;
5+
6+ // Helper to build tabs
7+ function makeTabs ( count = 3 ) : NavTabItem [ ] {
8+ return Array . from ( { length : count } , ( _ , i ) => ( {
9+ key : `TAB_${ i + 1 } ` ,
10+ title : `Tab ${ i + 1 } ` ,
11+ isClosable : false ,
12+ } ) ) ;
13+ }
14+
15+ // JSDOM doesn't implement scrollIntoView; stub to avoid errors triggered by effect
16+ window . HTMLElement . prototype . scrollIntoView = jest . fn ( ) ;
17+
18+ describe ( 'NavTabList renderAfterTabContent' , ( ) => {
19+ it ( 'renders content after tab title when renderAfterTabContent provided' , async ( ) => {
20+ const tabs = makeTabs ( 3 ) ;
21+ const user = userEvent . setup ( ) ;
22+ const onSelect = jest . fn ( ) ;
23+
24+ render (
25+ < NavTabList
26+ activeKey = { tabs [ 0 ] . key }
27+ tabs = { tabs }
28+ onSelect = { onSelect }
29+ renderAfterTabContent = { tab => < span > { `${ tab . title } -slot` } </ span > }
30+ />
31+ ) ;
32+
33+ // Assert each tab's content is rendered
34+ tabs . forEach ( tab => {
35+ expect ( screen . getByText ( `${ tab . title } -slot` ) ) . toBeInTheDocument ( ) ;
36+ } ) ;
37+
38+ // Selecting a tab still works with content present
39+ await user . click ( screen . getByText ( 'Tab 2' ) ) ;
40+ expect ( onSelect ) . toHaveBeenCalledWith ( 'TAB_2' ) ;
41+ } ) ;
42+ } ) ;
Original file line number Diff line number Diff line change @@ -106,6 +106,15 @@ type NavTabListProps<T extends NavTabItem = NavTabItem> = {
106106 * @returns Additional context items for the tab
107107 */
108108 makeContextActions ?: ( tab : T ) => ContextAction | ContextAction [ ] ;
109+
110+ /**
111+ * Optional render function to render content after each tab's title.
112+ * Should be wrapped in useCallback to avoid unnecessary re-renders.
113+ *
114+ * @param tab The tab to render content for
115+ * @returns The content to render after the tab title
116+ */
117+ renderAfterTabContent ?: ( tab : T ) => React . ReactNode ;
109118} ;
110119
111120function isScrolledLeft ( element : HTMLElement ) : boolean {
@@ -181,6 +190,7 @@ function NavTabList({
181190 onReorder,
182191 onClose,
183192 makeContextActions,
193+ renderAfterTabContent,
184194} : NavTabListProps ) : React . ReactElement {
185195 const containerRef = useRef < HTMLDivElement > ( ) ;
186196 const [ isOverflowing , setIsOverflowing ] = useState ( true ) ;
@@ -431,6 +441,7 @@ function NavTabList({
431441 onClose = { onClose }
432442 isDraggable = { onReorder != null }
433443 contextActions = { tabContextActionMap . get ( key ) }
444+ renderAfterTabContent = { renderAfterTabContent }
434445 />
435446 ) ;
436447 } ) ;
You can’t perform that action at this time.
0 commit comments