react-tab-set 1.2.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -3
- package/src/.babelrc +1 -0
- package/src/tab-set/index.tsx +77 -116
- package/src/tab-set/is-tab-group.mts +1 -1
- package/src/tab-set/is-tab-panel.mts +1 -1
- package/src/tab-set/tab-group/index.tsx +50 -79
- package/src/tab-set/tab-group/tab/index.tsx +23 -49
- package/src/tab-set/tab-panel/index.tsx +10 -41
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-tab-set",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A React Tab Set component",
|
|
5
5
|
"main": "./src/index.mjs",
|
|
6
6
|
"type": "module",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@babel/core": "^7.22.20",
|
|
33
33
|
"@babel/eslint-parser": "^7.22.15",
|
|
34
|
+
"@babel/plugin-syntax-jsx": "^7.22.5",
|
|
34
35
|
"@babel/plugin-transform-typescript": "^7.22.15",
|
|
35
36
|
"@babel/preset-env": "^7.22.20",
|
|
36
37
|
"@babel/preset-react": "^7.22.15",
|
|
@@ -54,8 +55,8 @@
|
|
|
54
55
|
"eslint-plugin-storybook": "^0.6.14",
|
|
55
56
|
"husky": "^8.0.3",
|
|
56
57
|
"prop-types": "15.7.2",
|
|
57
|
-
"react": "
|
|
58
|
-
"react-dom": "
|
|
58
|
+
"react": "^18.2.0",
|
|
59
|
+
"react-dom": "^18.2.0",
|
|
59
60
|
"storybook": "^7.4.4",
|
|
60
61
|
"typescript": "^5.2.2"
|
|
61
62
|
},
|
package/src/.babelrc
CHANGED
package/src/tab-set/index.tsx
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement,
|
|
4
|
+
useState,
|
|
5
|
+
useEffect
|
|
6
|
+
} from 'react'
|
|
2
7
|
import {
|
|
3
8
|
v4
|
|
4
9
|
} from 'uuid'
|
|
@@ -10,132 +15,88 @@ import isTabGroup from './is-tab-group.mts'
|
|
|
10
15
|
const error = debug('react-tab-set/tab-set')
|
|
11
16
|
|
|
12
17
|
export interface TabSetProps {
|
|
13
|
-
onClick: (selectedTab: string) => void
|
|
14
|
-
onChange: (selectedTab: string) => void
|
|
15
|
-
selectedTab: string
|
|
16
18
|
children: JSX.Element | JSX.Element[]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface TabSetState {
|
|
20
19
|
selectedTab: string
|
|
20
|
+
onChange: (selectedTab: string) => void
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
23
|
+
function mapChildren (
|
|
24
|
+
children: JSX.Element | JSX.Element[],
|
|
25
|
+
selectedTab: string,
|
|
26
|
+
onTabSelect: (value: React.SetStateAction<string>) => void): JSX.Element[] {
|
|
27
|
+
return Children.map(children, (child) => {
|
|
28
|
+
const { type } = child
|
|
29
|
+
|
|
30
|
+
if (type) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
31
|
+
const { props } = child
|
|
32
|
+
|
|
33
|
+
if (isTabGroup(type)) {
|
|
34
|
+
return cloneElement(
|
|
35
|
+
child,
|
|
36
|
+
{
|
|
37
|
+
...props,
|
|
38
|
+
selectedTab,
|
|
39
|
+
onTabSelect
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (isTabPanel(type)) {
|
|
45
|
+
return cloneElement(
|
|
46
|
+
child,
|
|
47
|
+
{
|
|
48
|
+
...props,
|
|
49
|
+
selectedTab
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const {
|
|
55
|
+
children
|
|
56
|
+
} = props
|
|
57
|
+
|
|
58
|
+
if (children) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
59
|
+
return cloneElement(
|
|
60
|
+
child,
|
|
61
|
+
{
|
|
62
|
+
...props,
|
|
63
|
+
children: mapChildren(children, selectedTab, onTabSelect)
|
|
64
|
+
}
|
|
65
|
+
)
|
|
66
|
+
}
|
|
43
67
|
}
|
|
44
|
-
}
|
|
45
68
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
69
|
+
return child
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default function TabSet (props: TabSetProps): JSX.Element {
|
|
74
|
+
const {
|
|
75
|
+
children,
|
|
76
|
+
selectedTab: tab
|
|
77
|
+
} = props
|
|
78
|
+
|
|
79
|
+
const [selectedTab, setSelectedTab] = useState(tab)
|
|
80
|
+
|
|
81
|
+
useEffect(() => { setSelectedTab(tab) }, [tab])
|
|
52
82
|
|
|
53
|
-
|
|
54
|
-
const {
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
const { onChange } = props
|
|
55
85
|
|
|
56
86
|
try {
|
|
57
|
-
|
|
87
|
+
onChange(selectedTab)
|
|
58
88
|
} catch {
|
|
59
|
-
error('Error `
|
|
89
|
+
error('Error `onChange`')
|
|
60
90
|
}
|
|
91
|
+
}, [selectedTab])
|
|
61
92
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
} catch {
|
|
69
|
-
error('Error `onChange`')
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
mapChildren (children: JSX.Element | JSX.Element[], selectedTab: string): JSX.Element[] {
|
|
76
|
-
return Children.map(children, (child) => {
|
|
77
|
-
const { type } = child
|
|
78
|
-
|
|
79
|
-
if (type) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
80
|
-
const { props } = child
|
|
81
|
-
|
|
82
|
-
if (isTabGroup(type)) {
|
|
83
|
-
return cloneElement(
|
|
84
|
-
child,
|
|
85
|
-
{
|
|
86
|
-
...props,
|
|
87
|
-
selectedTab,
|
|
88
|
-
onTabSelect: this.handleTabSelect
|
|
89
|
-
}
|
|
90
|
-
)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (isTabPanel(type)) {
|
|
94
|
-
return cloneElement(
|
|
95
|
-
child,
|
|
96
|
-
{
|
|
97
|
-
...props,
|
|
98
|
-
selectedTab
|
|
99
|
-
}
|
|
100
|
-
)
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const {
|
|
104
|
-
children
|
|
105
|
-
} = props
|
|
106
|
-
|
|
107
|
-
if (children) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
108
|
-
return cloneElement(
|
|
109
|
-
child,
|
|
110
|
-
{
|
|
111
|
-
...props,
|
|
112
|
-
children: this.mapChildren(children, selectedTab)
|
|
113
|
-
}
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
}
|
|
93
|
+
return (
|
|
94
|
+
<div className='selectedTab-set'>
|
|
95
|
+
{mapChildren(children, selectedTab, setSelectedTab)}
|
|
96
|
+
</div>
|
|
97
|
+
)
|
|
98
|
+
}
|
|
117
99
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
getChildren (): JSX.Element[] {
|
|
123
|
-
const {
|
|
124
|
-
children
|
|
125
|
-
} = this.props
|
|
126
|
-
|
|
127
|
-
const {
|
|
128
|
-
selectedTab
|
|
129
|
-
} = this.state
|
|
130
|
-
|
|
131
|
-
return this.mapChildren(children, selectedTab)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
render (): JSX.Element {
|
|
135
|
-
return (
|
|
136
|
-
<div className='tab-set'>
|
|
137
|
-
{this.getChildren()}
|
|
138
|
-
</div>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
100
|
+
TabSet.defaultProps = {
|
|
101
|
+
selectedTab: v4()
|
|
141
102
|
}
|
|
@@ -1,92 +1,63 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from '
|
|
1
|
+
import React, {
|
|
2
|
+
Children,
|
|
3
|
+
cloneElement
|
|
4
|
+
} from 'react'
|
|
5
5
|
|
|
6
6
|
import isTab from './is-tab.mts'
|
|
7
7
|
|
|
8
8
|
export interface TabGroupProps {
|
|
9
|
-
onTabSelect: (selectedTab: string) => void
|
|
10
9
|
children: JSX.Element | JSX.Element[]
|
|
11
10
|
selectedTab: string
|
|
11
|
+
onTabSelect: (value: React.SetStateAction<string>) => void
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
handleTabClick = (tab: string): void => {
|
|
34
|
-
const { onTabSelect } = this.props
|
|
35
|
-
|
|
36
|
-
onTabSelect(tab)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
mapChildren (children: JSX.Element | JSX.Element[], selectedTab: string): JSX.Element[] {
|
|
40
|
-
return Children.map(children, (child) => {
|
|
41
|
-
const { type } = child
|
|
42
|
-
|
|
43
|
-
if (type) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
44
|
-
const { props } = child
|
|
45
|
-
|
|
46
|
-
if (isTab(type)) {
|
|
47
|
-
return cloneElement(
|
|
48
|
-
child,
|
|
49
|
-
{
|
|
50
|
-
...props,
|
|
51
|
-
selectedTab,
|
|
52
|
-
onTabClick: this.handleTabClick
|
|
53
|
-
}
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const {
|
|
58
|
-
children
|
|
59
|
-
} = props
|
|
60
|
-
|
|
61
|
-
if (children) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
62
|
-
return cloneElement(
|
|
63
|
-
child,
|
|
64
|
-
{
|
|
65
|
-
...props,
|
|
66
|
-
children: this.mapChildren(children, selectedTab)
|
|
67
|
-
}
|
|
68
|
-
)
|
|
69
|
-
}
|
|
14
|
+
function mapChildren (children: JSX.Element | JSX.Element[], selectedTab: string, onTabSelect: (value: React.SetStateAction<string>) => void): JSX.Element[] {
|
|
15
|
+
return Children.map(children, (child) => {
|
|
16
|
+
const { type } = child
|
|
17
|
+
|
|
18
|
+
if (type) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
19
|
+
const { props } = child
|
|
20
|
+
|
|
21
|
+
if (isTab(type)) {
|
|
22
|
+
return cloneElement(
|
|
23
|
+
child,
|
|
24
|
+
{
|
|
25
|
+
...props,
|
|
26
|
+
selectedTab,
|
|
27
|
+
onTabSelect
|
|
28
|
+
}
|
|
29
|
+
)
|
|
70
30
|
}
|
|
71
31
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
32
|
+
const {
|
|
33
|
+
children
|
|
34
|
+
} = props
|
|
35
|
+
|
|
36
|
+
if (children) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
37
|
+
return cloneElement(
|
|
38
|
+
child,
|
|
39
|
+
{
|
|
40
|
+
...props,
|
|
41
|
+
children: mapChildren(children, selectedTab, onTabSelect)
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
81
46
|
|
|
82
|
-
return
|
|
83
|
-
}
|
|
47
|
+
return child
|
|
48
|
+
})
|
|
49
|
+
}
|
|
84
50
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
51
|
+
export default function TabGroup (props: TabGroupProps): JSX.Element {
|
|
52
|
+
const {
|
|
53
|
+
children,
|
|
54
|
+
selectedTab,
|
|
55
|
+
onTabSelect
|
|
56
|
+
} = props
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<ul className='tab-group'>
|
|
60
|
+
{mapChildren(children, selectedTab, onTabSelect)}
|
|
61
|
+
</ul>
|
|
62
|
+
)
|
|
92
63
|
}
|
|
@@ -1,57 +1,31 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
v4
|
|
4
|
-
} from 'uuid'
|
|
1
|
+
import React from 'react'
|
|
5
2
|
|
|
6
3
|
export interface TabProps {
|
|
7
|
-
onTabClick: (tab: string) => void
|
|
8
4
|
children: JSX.Element | JSX.Element[] | string | number | boolean
|
|
9
5
|
tab: string
|
|
10
6
|
selectedTab: string
|
|
7
|
+
onTabSelect: (value: React.SetStateAction<string>) => void
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
export default
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
handleClick = (): void => {
|
|
35
|
-
const { tab, onTabClick } = this.props
|
|
36
|
-
|
|
37
|
-
onTabClick(tab)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
render (): JSX.Element {
|
|
41
|
-
const {
|
|
42
|
-
tab,
|
|
43
|
-
selectedTab,
|
|
44
|
-
children
|
|
45
|
-
} = this.props
|
|
46
|
-
|
|
47
|
-
const className = (tab === selectedTab)
|
|
48
|
-
? 'tab selected'
|
|
49
|
-
: 'tab'
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<li className={className} onClick={this.handleClick}>
|
|
53
|
-
{children}
|
|
54
|
-
</li>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
10
|
+
export default function Tab (props: TabProps): JSX.Element {
|
|
11
|
+
const {
|
|
12
|
+
children,
|
|
13
|
+
tab,
|
|
14
|
+
selectedTab,
|
|
15
|
+
onTabSelect
|
|
16
|
+
} = props
|
|
17
|
+
|
|
18
|
+
const className = (tab === selectedTab)
|
|
19
|
+
? 'tab selected'
|
|
20
|
+
: 'tab'
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<li
|
|
24
|
+
className={className}
|
|
25
|
+
onClick={(): void => {
|
|
26
|
+
onTabSelect(tab)
|
|
27
|
+
}}>
|
|
28
|
+
{children}
|
|
29
|
+
</li>
|
|
30
|
+
)
|
|
57
31
|
}
|
|
@@ -1,41 +1,23 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import {
|
|
3
|
-
v4
|
|
4
|
-
} from 'uuid'
|
|
1
|
+
import React from 'react'
|
|
5
2
|
|
|
6
3
|
export interface TabPanelProps {
|
|
7
|
-
children
|
|
4
|
+
children?: JSX.Element | JSX.Element[] | string | number | boolean | undefined | null
|
|
8
5
|
tab: string
|
|
9
6
|
selectedTab: string
|
|
10
7
|
render?: () => JSX.Element | JSX.Element[] | string | number | boolean | undefined | null
|
|
11
8
|
}
|
|
12
9
|
|
|
13
|
-
export default
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/
|
|
19
|
-
static defaultProps = {
|
|
20
|
-
tab: v4(),
|
|
21
|
-
selectedTab: v4()
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
shouldComponentUpdate (props: TabPanelProps): boolean {
|
|
25
|
-
if (props.render instanceof Function) return true
|
|
10
|
+
export default function TabPanel (props: TabPanelProps): JSX.Element | null {
|
|
11
|
+
const {
|
|
12
|
+
tab,
|
|
13
|
+
selectedTab
|
|
14
|
+
} = props
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
props.children !== this.props.children ||
|
|
29
|
-
props.tab !== this.props.tab ||
|
|
30
|
-
props.selectedTab !== this.props.selectedTab
|
|
31
|
-
)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
renderPanel (): JSX.Element | null {
|
|
16
|
+
if (tab === selectedTab) {
|
|
35
17
|
const {
|
|
36
18
|
render = () => null,
|
|
37
19
|
children = render()
|
|
38
|
-
} =
|
|
20
|
+
} = props
|
|
39
21
|
|
|
40
22
|
if (children) { // eslint-disable-line @typescript-eslint/strict-boolean-expressions
|
|
41
23
|
return (
|
|
@@ -44,20 +26,7 @@ export default class TabPanel extends Component<TabPanelProps> {
|
|
|
44
26
|
</div>
|
|
45
27
|
)
|
|
46
28
|
}
|
|
47
|
-
|
|
48
|
-
return null
|
|
49
29
|
}
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
const {
|
|
53
|
-
tab,
|
|
54
|
-
selectedTab
|
|
55
|
-
} = this.props
|
|
56
|
-
|
|
57
|
-
if (tab === selectedTab) {
|
|
58
|
-
return this.renderPanel()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return null
|
|
62
|
-
}
|
|
31
|
+
return null
|
|
63
32
|
}
|