@clayui/tabs 3.86.0 → 3.87.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/lib/Item.d.ts +4 -0
- package/lib/List.d.ts +5 -1
- package/lib/List.js +25 -2
- package/lib/index.js +4 -2
- package/package.json +3 -3
- package/src/Item.tsx +4 -0
- package/src/List.tsx +30 -1
- package/src/__tests__/index.tsx +21 -0
- package/src/index.tsx +2 -1
package/lib/Item.d.ts
CHANGED
|
@@ -6,6 +6,10 @@ import React from 'react';
|
|
|
6
6
|
export interface IProps extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {
|
|
7
7
|
/**
|
|
8
8
|
* Flag to indicate if the component is active or not.
|
|
9
|
+
*
|
|
10
|
+
* OBS: The `active` API in the new pattern has uncontrolled behavior,
|
|
11
|
+
* working just like `defaultActive` as in the prop declared in the
|
|
12
|
+
* root component.
|
|
9
13
|
*/
|
|
10
14
|
active?: boolean;
|
|
11
15
|
/**
|
package/lib/List.d.ts
CHANGED
|
@@ -37,12 +37,16 @@ export interface IProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
|
37
37
|
* @ignore
|
|
38
38
|
*/
|
|
39
39
|
onActiveChange?: InternalDispatch<number>;
|
|
40
|
+
/**
|
|
41
|
+
* @ignore
|
|
42
|
+
*/
|
|
43
|
+
shouldUseActive?: boolean;
|
|
40
44
|
/**
|
|
41
45
|
* @ignore
|
|
42
46
|
*/
|
|
43
47
|
tabsId?: string;
|
|
44
48
|
}
|
|
45
|
-
export declare function List({ activation, active, children, className, displayType, justified, modern, onActiveChange, tabsId, ...otherProps }: IProps): JSX.Element;
|
|
49
|
+
export declare function List({ activation, active, children, className, displayType, justified, modern, onActiveChange, shouldUseActive, tabsId, ...otherProps }: IProps): JSX.Element;
|
|
46
50
|
export declare namespace List {
|
|
47
51
|
var displayName: string;
|
|
48
52
|
}
|
package/lib/List.js
CHANGED
|
@@ -13,7 +13,7 @@ var _classnames = _interopRequireDefault(require("classnames"));
|
|
|
13
13
|
|
|
14
14
|
var _react = _interopRequireWildcard(require("react"));
|
|
15
15
|
|
|
16
|
-
var _excluded = ["activation", "active", "children", "className", "displayType", "justified", "modern", "onActiveChange", "tabsId"];
|
|
16
|
+
var _excluded = ["activation", "active", "children", "className", "displayType", "justified", "modern", "onActiveChange", "shouldUseActive", "tabsId"];
|
|
17
17
|
|
|
18
18
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
19
19
|
|
|
@@ -42,6 +42,8 @@ function List(_ref) {
|
|
|
42
42
|
justified = _ref.justified,
|
|
43
43
|
modern = _ref.modern,
|
|
44
44
|
onActiveChange = _ref.onActiveChange,
|
|
45
|
+
_ref$shouldUseActive = _ref.shouldUseActive,
|
|
46
|
+
shouldUseActive = _ref$shouldUseActive === void 0 ? false : _ref$shouldUseActive,
|
|
45
47
|
tabsId = _ref.tabsId,
|
|
46
48
|
otherProps = _objectWithoutProperties(_ref, _excluded);
|
|
47
49
|
|
|
@@ -54,6 +56,27 @@ function List(_ref) {
|
|
|
54
56
|
}),
|
|
55
57
|
navigationProps = _useNavigation.navigationProps;
|
|
56
58
|
|
|
59
|
+
(0, _react.useEffect)(function () {
|
|
60
|
+
// Internal API to maintain compatibility with the old Tabs pattern and to
|
|
61
|
+
// only update the initial state when the component is in
|
|
62
|
+
// uncontrolled mode.
|
|
63
|
+
if (!shouldUseActive) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
var childrenArray = _react.default.Children.toArray(children); // The `active` API in the new pattern has uncontrolled behavior, working
|
|
68
|
+
// just like defaultActive as in the prop declared in the root component.
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
for (var index = 0; index < childrenArray.length; index++) {
|
|
72
|
+
var child = childrenArray[index];
|
|
73
|
+
|
|
74
|
+
if ( /*#__PURE__*/_react.default.isValidElement(child) && child.props.active) {
|
|
75
|
+
onActiveChange(index);
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}, []);
|
|
57
80
|
return /*#__PURE__*/_react.default.createElement("ul", _extends({}, otherProps, navigationProps, {
|
|
58
81
|
className: (0, _classnames.default)('nav', {
|
|
59
82
|
'nav-justified': justified
|
|
@@ -74,7 +97,7 @@ function List(_ref) {
|
|
|
74
97
|
}
|
|
75
98
|
|
|
76
99
|
return /*#__PURE__*/_react.default.cloneElement(child, {
|
|
77
|
-
active: child.props.active !== undefined ? child.props.active : active === index,
|
|
100
|
+
active: !shouldUseActive && child.props.active !== undefined ? child.props.active : active === index,
|
|
78
101
|
innerProps: _objectSpread({
|
|
79
102
|
'aria-controls': tabsId && "".concat(tabsId, "-tabpanel-").concat(index),
|
|
80
103
|
id: tabsId && "".concat(tabsId, "-tab-").concat(index)
|
package/lib/index.js
CHANGED
|
@@ -66,9 +66,10 @@ function ClayTabs(_ref) {
|
|
|
66
66
|
onChange: onActiveChange,
|
|
67
67
|
value: externalActive
|
|
68
68
|
}),
|
|
69
|
-
_useInternalState2 = _slicedToArray(_useInternalState,
|
|
69
|
+
_useInternalState2 = _slicedToArray(_useInternalState, 3),
|
|
70
70
|
active = _useInternalState2[0],
|
|
71
|
-
setActive = _useInternalState2[1]
|
|
71
|
+
setActive = _useInternalState2[1],
|
|
72
|
+
isUncontrolled = _useInternalState2[2];
|
|
72
73
|
|
|
73
74
|
var _React$Children$toArr = _react.default.Children.toArray(children),
|
|
74
75
|
_React$Children$toArr2 = _slicedToArray(_React$Children$toArr, 2),
|
|
@@ -85,6 +86,7 @@ function ClayTabs(_ref) {
|
|
|
85
86
|
justified: justified,
|
|
86
87
|
modern: modern,
|
|
87
88
|
onActiveChange: setActive,
|
|
89
|
+
shouldUseActive: isUncontrolled,
|
|
88
90
|
tabsId: tabsId
|
|
89
91
|
}), /*#__PURE__*/_react.default.isValidElement(right) && /*#__PURE__*/_react.default.cloneElement(right, {
|
|
90
92
|
active: active,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clayui/tabs",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.87.0",
|
|
4
4
|
"description": "ClayTabs component",
|
|
5
5
|
"license": "BSD-3-Clause",
|
|
6
6
|
"repository": "https://github.com/liferay/clay",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"react"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@clayui/shared": "^3.
|
|
29
|
+
"@clayui/shared": "^3.87.0",
|
|
30
30
|
"classnames": "^2.2.6"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
@@ -37,5 +37,5 @@
|
|
|
37
37
|
"browserslist": [
|
|
38
38
|
"extends browserslist-config-clay"
|
|
39
39
|
],
|
|
40
|
-
"gitHead": "
|
|
40
|
+
"gitHead": "f071126e11f2c0ddeab525b5c14eb83f984f6f37"
|
|
41
41
|
}
|
package/src/Item.tsx
CHANGED
|
@@ -11,6 +11,10 @@ export interface IProps
|
|
|
11
11
|
extends Omit<React.HTMLAttributes<HTMLLIElement>, 'onClick'> {
|
|
12
12
|
/**
|
|
13
13
|
* Flag to indicate if the component is active or not.
|
|
14
|
+
*
|
|
15
|
+
* OBS: The `active` API in the new pattern has uncontrolled behavior,
|
|
16
|
+
* working just like `defaultActive` as in the prop declared in the
|
|
17
|
+
* root component.
|
|
14
18
|
*/
|
|
15
19
|
active?: boolean;
|
|
16
20
|
|
package/src/List.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import {InternalDispatch, useNavigation} from '@clayui/shared';
|
|
7
7
|
import classNames from 'classnames';
|
|
8
|
-
import React, {useRef} from 'react';
|
|
8
|
+
import React, {useEffect, useRef} from 'react';
|
|
9
9
|
|
|
10
10
|
export interface IProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
11
11
|
/**
|
|
@@ -48,6 +48,11 @@ export interface IProps extends React.HTMLAttributes<HTMLUListElement> {
|
|
|
48
48
|
*/
|
|
49
49
|
onActiveChange?: InternalDispatch<number>;
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @ignore
|
|
53
|
+
*/
|
|
54
|
+
shouldUseActive?: boolean;
|
|
55
|
+
|
|
51
56
|
/**
|
|
52
57
|
* @ignore
|
|
53
58
|
*/
|
|
@@ -63,6 +68,7 @@ export function List({
|
|
|
63
68
|
justified,
|
|
64
69
|
modern,
|
|
65
70
|
onActiveChange,
|
|
71
|
+
shouldUseActive = false,
|
|
66
72
|
tabsId,
|
|
67
73
|
...otherProps
|
|
68
74
|
}: IProps) {
|
|
@@ -74,6 +80,28 @@ export function List({
|
|
|
74
80
|
orientation: 'horizontal',
|
|
75
81
|
});
|
|
76
82
|
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
// Internal API to maintain compatibility with the old Tabs pattern and to
|
|
85
|
+
// only update the initial state when the component is in
|
|
86
|
+
// uncontrolled mode.
|
|
87
|
+
if (!shouldUseActive) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const childrenArray = React.Children.toArray(children);
|
|
92
|
+
|
|
93
|
+
// The `active` API in the new pattern has uncontrolled behavior, working
|
|
94
|
+
// just like defaultActive as in the prop declared in the root component.
|
|
95
|
+
for (let index = 0; index < childrenArray.length; index++) {
|
|
96
|
+
const child = childrenArray[index];
|
|
97
|
+
|
|
98
|
+
if (React.isValidElement(child) && child.props.active) {
|
|
99
|
+
onActiveChange!(index);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}, []);
|
|
104
|
+
|
|
77
105
|
return (
|
|
78
106
|
<ul
|
|
79
107
|
{...otherProps}
|
|
@@ -103,6 +131,7 @@ export function List({
|
|
|
103
131
|
|
|
104
132
|
return React.cloneElement(child as React.ReactElement, {
|
|
105
133
|
active:
|
|
134
|
+
!shouldUseActive &&
|
|
106
135
|
(child as React.ReactElement).props.active !== undefined
|
|
107
136
|
? (child as React.ReactElement).props.active
|
|
108
137
|
: active === index,
|
package/src/__tests__/index.tsx
CHANGED
|
@@ -192,4 +192,25 @@ describe('ClayTabs', () => {
|
|
|
192
192
|
expect(getAllByRole('tab').length).toBe(3);
|
|
193
193
|
expect(getAllByRole('tabpanel').length).toBe(3);
|
|
194
194
|
});
|
|
195
|
+
|
|
196
|
+
it('renders the tab item active when `active` is set on uncontrolled state', () => {
|
|
197
|
+
const {getByRole} = render(
|
|
198
|
+
<ClayTabs>
|
|
199
|
+
<ClayTabs.List>
|
|
200
|
+
<ClayTabs.Item>Tab 1</ClayTabs.Item>
|
|
201
|
+
<ClayTabs.Item active>Tab 2</ClayTabs.Item>
|
|
202
|
+
<ClayTabs.Item>Tab 3</ClayTabs.Item>
|
|
203
|
+
</ClayTabs.List>
|
|
204
|
+
<ClayTabs.Panels>
|
|
205
|
+
<ClayTabs.TabPanel>Tab Content 1</ClayTabs.TabPanel>
|
|
206
|
+
<ClayTabs.TabPanel>Tab Content 2</ClayTabs.TabPanel>
|
|
207
|
+
<ClayTabs.TabPanel>Tab Content 3</ClayTabs.TabPanel>
|
|
208
|
+
</ClayTabs.Panels>
|
|
209
|
+
</ClayTabs>
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
const activeTab = getByRole('tab', {selected: true});
|
|
213
|
+
|
|
214
|
+
expect(activeTab.innerHTML).toBe('Tab 2');
|
|
215
|
+
});
|
|
195
216
|
});
|
package/src/index.tsx
CHANGED
|
@@ -82,7 +82,7 @@ function ClayTabs({
|
|
|
82
82
|
onActiveChange,
|
|
83
83
|
...otherProps
|
|
84
84
|
}: IProps) {
|
|
85
|
-
const [active, setActive] = useInternalState({
|
|
85
|
+
const [active, setActive, isUncontrolled] = useInternalState({
|
|
86
86
|
defaultName: 'defaultActive',
|
|
87
87
|
defaultValue: defaultActive,
|
|
88
88
|
handleName: 'onActiveChange',
|
|
@@ -106,6 +106,7 @@ function ClayTabs({
|
|
|
106
106
|
justified,
|
|
107
107
|
modern,
|
|
108
108
|
onActiveChange: setActive,
|
|
109
|
+
shouldUseActive: isUncontrolled,
|
|
109
110
|
tabsId,
|
|
110
111
|
})}
|
|
111
112
|
|