1
1
import * as React from "react" ;
2
2
import { Tabs as ReactTabs , TabList , TabPanel } from "react-tabs" ;
3
3
import { injectGlobal , cx } from "@emotion/css" ;
4
-
4
+ import uuid from "uuid" ;
5
5
import { TabItemProps } from "./TabItem" ;
6
6
import { TabTitle } from ".." ;
7
7
import {
@@ -13,9 +13,7 @@ import {
13
13
import { listReset } from "../../shared/styles/styleUtils" ;
14
14
import { BreakpointConfig } from "../../shared/styles/breakpoints" ;
15
15
import { fullHeightTabs , getTabLayout } from "../style" ;
16
-
17
16
export const defaultTabDirection = "horiz" ;
18
-
19
17
// Copy & paste from node_modules/react-tabs/style/react-tabs.css
20
18
// Also changed to better fit the ui kit styles.
21
19
// This is needed to give the tabs a style
@@ -24,53 +22,44 @@ injectGlobal`
24
22
.react-tabs {
25
23
-webkit-tap-highlight-color: transparent;
26
24
}
27
-
28
25
.react-tabs__tab-list {
29
26
${ listReset } ;
30
27
}
31
-
32
28
.react-tabs__tab {
33
29
position: relative;
34
30
cursor: pointer;
35
31
font-weight: ${ fontWeightMedium } ;
36
32
color: ${ themeTextColorPrimary } ;
37
-
38
33
&:after{
39
34
content: "";
40
35
position: absolute;
41
36
background: ${ themeBrandPrimary } ;
42
37
display: none;
43
38
}
44
39
}
45
-
46
40
.react-tabs__tab:focus {
47
41
outline: none;
48
42
background: ${ themeBgHover }
49
43
}
50
-
51
44
.react-tabs__tab--selected {
52
45
&:after{
53
46
display: block;
54
47
}
55
48
color: ${ themeBrandPrimary } ;
56
49
}
57
-
58
50
.react-tabs__tab--disabled {
59
51
color: GrayText;
60
52
cursor: default;
61
53
}
62
-
63
54
.react-tabs__tab-panel {
64
55
display: none;
65
56
flex-grow: 1;
66
57
}
67
-
68
58
.react-tabs__tab-panel--selected {
69
59
display: block;
70
60
}
71
61
` ;
72
62
/* eslint-enable */
73
-
74
63
export type TabDirections = "horiz" | "vert" ;
75
64
export type TabDirection = BreakpointConfig < TabDirections > ;
76
65
export type TabSelected = string ;
@@ -82,52 +71,55 @@ export interface TabsProps {
82
71
onSelect ?: ( tabIndex : number ) => void ;
83
72
direction ?: TabDirection ;
84
73
}
85
-
86
74
const Tabs = ( {
87
75
children,
88
76
selectedIndex,
89
77
onSelect,
90
78
direction = defaultTabDirection
91
79
} : TabsProps ) => {
92
- const { tabs, tabsContent } = (
93
- React . Children . toArray ( children ) as Array < React . ReactElement < TabItemProps > >
94
- )
95
- . filter ( item => React . isValidElement < TabItemProps > ( item ) )
96
- . reduce < {
97
- tabs : React . ReactNode [ ] ;
98
- tabsContent : React . ReactNode [ ] ;
99
- } > (
100
- ( acc , item ) => {
101
- const { tabs = [ ] , tabsContent = [ ] } = acc ;
102
- const { children } = item . props ;
103
- const key = item . key ? item . key : undefined ;
104
- const childrenWithKeys = React . Children . toArray ( children ) . map ( child =>
105
- React . isValidElement < typeof TabTitle > ( child )
106
- ? React . cloneElement ( child , { key } )
107
- : child
108
- ) ;
109
-
110
- const title = childrenWithKeys . find (
111
- child =>
112
- React . isValidElement < typeof TabTitle > ( child ) &&
113
- child . type === TabTitle
114
- ) ;
115
- const tabChildren = childrenWithKeys . filter (
116
- child => ! ( React . isValidElement ( child ) && child . type === TabTitle )
117
- ) ;
118
- return {
119
- tabs : [ ...tabs , title ] ,
120
- tabsContent : [
121
- ...tabsContent ,
122
- ...( tabChildren . length
123
- ? [ < TabPanel key = { key } > { tabChildren } </ TabPanel > ]
124
- : [ ] )
125
- ]
126
- } ;
127
- } ,
128
- { tabs : [ ] , tabsContent : [ ] }
129
- ) ;
130
-
80
+ const { tabs, tabsContent } = React . useMemo ( ( ) => {
81
+ return (
82
+ React . Children . toArray ( children ) as Array <
83
+ React . ReactElement < TabItemProps >
84
+ >
85
+ )
86
+ . filter ( item => React . isValidElement < TabItemProps > ( item ) )
87
+ . reduce < {
88
+ tabs : React . ReactNode [ ] ;
89
+ tabsContent : React . ReactNode [ ] ;
90
+ } > (
91
+ ( acc , item ) => {
92
+ const { tabs = [ ] , tabsContent = [ ] } = acc ;
93
+ const { children } = item . props ;
94
+ const key = item . key ? item . key : undefined ;
95
+ const childrenWithKeys = React . Children . toArray ( children ) . map (
96
+ child => {
97
+ return React . isValidElement < typeof TabTitle > ( child )
98
+ ? React . cloneElement ( child , { key : `${ key } -${ uuid ( ) } ` } )
99
+ : child ;
100
+ }
101
+ ) ;
102
+ const title = childrenWithKeys . find (
103
+ child =>
104
+ React . isValidElement < typeof TabTitle > ( child ) &&
105
+ child . type === TabTitle
106
+ ) ;
107
+ const tabChildren = childrenWithKeys . filter (
108
+ child => ! ( React . isValidElement ( child ) && child . type === TabTitle )
109
+ ) ;
110
+ return {
111
+ tabs : [ ...tabs , title ] ,
112
+ tabsContent : [
113
+ ...tabsContent ,
114
+ ...( tabChildren . length
115
+ ? [ < TabPanel key = { key } > { tabChildren } </ TabPanel > ]
116
+ : [ ] )
117
+ ]
118
+ } ;
119
+ } ,
120
+ { tabs : [ ] , tabsContent : [ ] }
121
+ ) ;
122
+ } , [ children ] ) ;
131
123
return (
132
124
< ReactTabs
133
125
className = { cx ( "react-tabs" , {
@@ -146,5 +138,4 @@ const Tabs = ({
146
138
</ ReactTabs >
147
139
) ;
148
140
} ;
149
-
150
141
export default React . memo ( Tabs ) ;
0 commit comments