@itwin/itwinui-react 3.0.0-dev.12 → 3.0.0-dev.14
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/CHANGELOG.md +43 -0
- package/cjs/core/Carousel/Carousel.d.ts +12 -5
- package/cjs/core/Carousel/Carousel.js +9 -39
- package/cjs/core/Carousel/CarouselContext.d.ts +0 -4
- package/cjs/core/Carousel/CarouselDot.js +1 -1
- package/cjs/core/Carousel/CarouselDotsList.js +26 -2
- package/cjs/core/Carousel/CarouselNavigation.d.ts +1 -1
- package/cjs/core/Carousel/CarouselNavigation.js +4 -17
- package/cjs/core/Carousel/CarouselSlide.d.ts +1 -1
- package/cjs/core/Carousel/CarouselSlide.js +12 -2
- package/cjs/core/Carousel/CarouselSlider.d.ts +1 -1
- package/cjs/core/Carousel/CarouselSlider.js +2 -2
- package/cjs/core/ColorPicker/ColorBuilder.js +2 -0
- package/cjs/core/ColorPicker/ColorInputPanel.js +24 -4
- package/cjs/core/ColorPicker/ColorPalette.js +2 -80
- package/cjs/core/ColorPicker/ColorSwatch.d.ts +1 -1
- package/cjs/core/ColorPicker/ColorSwatch.js +25 -15
- package/cjs/core/LabeledSelect/LabeledSelect.d.ts +1 -1
- package/cjs/core/LabeledSelect/LabeledSelect.js +3 -3
- package/cjs/core/Select/Select.d.ts +1 -1
- package/cjs/core/Select/Select.js +6 -4
- package/cjs/core/Slider/Slider.d.ts +2 -6
- package/cjs/core/Slider/Slider.js +8 -22
- package/cjs/core/Slider/Thumb.d.ts +1 -2
- package/cjs/core/Slider/Thumb.js +1 -5
- package/cjs/core/Tabs/Tabs.d.ts +222 -52
- package/cjs/core/Tabs/Tabs.js +429 -375
- package/cjs/core/ThemeProvider/ThemeProvider.js +3 -1
- package/cjs/core/Tile/Tile.js +11 -10
- package/cjs/core/utils/hooks/useOverflow.js +3 -1
- package/cjs/index.d.ts +1 -2
- package/cjs/index.js +1 -2
- package/cjs/styles.js +10 -10
- package/esm/core/Carousel/Carousel.d.ts +12 -5
- package/esm/core/Carousel/Carousel.js +9 -39
- package/esm/core/Carousel/CarouselContext.d.ts +0 -4
- package/esm/core/Carousel/CarouselDot.js +1 -1
- package/esm/core/Carousel/CarouselDotsList.js +26 -2
- package/esm/core/Carousel/CarouselNavigation.d.ts +1 -1
- package/esm/core/Carousel/CarouselNavigation.js +5 -22
- package/esm/core/Carousel/CarouselSlide.d.ts +1 -1
- package/esm/core/Carousel/CarouselSlide.js +15 -3
- package/esm/core/Carousel/CarouselSlider.d.ts +1 -1
- package/esm/core/Carousel/CarouselSlider.js +2 -2
- package/esm/core/ColorPicker/ColorBuilder.js +2 -0
- package/esm/core/ColorPicker/ColorInputPanel.js +25 -5
- package/esm/core/ColorPicker/ColorPalette.js +3 -83
- package/esm/core/ColorPicker/ColorSwatch.d.ts +1 -1
- package/esm/core/ColorPicker/ColorSwatch.js +18 -12
- package/esm/core/LabeledSelect/LabeledSelect.d.ts +1 -1
- package/esm/core/LabeledSelect/LabeledSelect.js +3 -2
- package/esm/core/Select/Select.d.ts +1 -1
- package/esm/core/Select/Select.js +3 -3
- package/esm/core/Slider/Slider.d.ts +2 -6
- package/esm/core/Slider/Slider.js +8 -19
- package/esm/core/Slider/Thumb.d.ts +1 -2
- package/esm/core/Slider/Thumb.js +1 -5
- package/esm/core/Tabs/Tabs.d.ts +222 -52
- package/esm/core/Tabs/Tabs.js +424 -368
- package/esm/core/ThemeProvider/ThemeProvider.js +3 -1
- package/esm/core/Tile/Tile.js +11 -10
- package/esm/core/utils/hooks/useOverflow.js +3 -1
- package/esm/index.d.ts +1 -2
- package/esm/index.js +1 -2
- package/esm/styles.js +10 -10
- package/package.json +2 -2
- package/styles.css +33 -47
- package/cjs/core/Tabs/Tab.d.ts +0 -40
- package/cjs/core/Tabs/Tab.js +0 -65
- package/esm/core/Tabs/Tab.d.ts +0 -40
- package/esm/core/Tabs/Tab.js +0 -57
package/cjs/core/Tabs/Tabs.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
3
|
-
exports.Tabs = void 0;
|
|
3
|
+
exports.Tabs = exports.Tab = void 0;
|
|
4
4
|
const tslib_1 = require('tslib');
|
|
5
5
|
/*---------------------------------------------------------------------------------------------
|
|
6
6
|
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
|
|
@@ -9,450 +9,504 @@ const tslib_1 = require('tslib');
|
|
|
9
9
|
const classnames_1 = tslib_1.__importDefault(require('classnames'));
|
|
10
10
|
const React = tslib_1.__importStar(require('react'));
|
|
11
11
|
const index_js_1 = require('../utils/index.js');
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
/**
|
|
15
|
-
* Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.
|
|
16
|
-
* @example
|
|
17
|
-
* const tabs = [
|
|
18
|
-
* <Tab label='Label 1' />,
|
|
19
|
-
* <Tab label='Label 2' />,
|
|
20
|
-
* <Tab label='Label 3' />,
|
|
21
|
-
* ];
|
|
22
|
-
* <Tabs labels={tabs} />
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* <Tabs orientation='vertical' labels={tabs} />
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* const tabsWithSublabels = [
|
|
29
|
-
* <Tab label='Label 1' sublabel='First tab' />,
|
|
30
|
-
* <Tab label='Label 2' sublabel='Active tab' />,
|
|
31
|
-
* ];
|
|
32
|
-
* <Tabs labels={tabsWithSublabels} activeIndex={1} />
|
|
33
|
-
*
|
|
34
|
-
* @example
|
|
35
|
-
* const tabsWithIcons = [
|
|
36
|
-
* <Tab label='Label 1' icon={<SvgPlaceholder />} />,
|
|
37
|
-
* <Tab label='Label 2' icon={<SvgPlaceholder />} />,
|
|
38
|
-
* ];
|
|
39
|
-
* <Tabs labels={tabsWithIcons} type='pill' />
|
|
40
|
-
*/
|
|
41
|
-
const Tabs = (props) => {
|
|
42
|
-
// Separate actions from props to avoid adding it to the DOM (using {...rest})
|
|
43
|
-
let actions;
|
|
44
|
-
if (props.type !== 'pill' && props.actions) {
|
|
45
|
-
actions = props.actions;
|
|
46
|
-
props = { ...props };
|
|
47
|
-
delete props.actions;
|
|
48
|
-
}
|
|
49
|
-
// Separate overflowOptions from props to avoid adding it to the DOM (using {...rest})
|
|
50
|
-
let overflowOptions;
|
|
51
|
-
if (
|
|
52
|
-
props.type !== 'borderless' &&
|
|
53
|
-
props.type !== 'pill' &&
|
|
54
|
-
props.overflowOptions
|
|
55
|
-
) {
|
|
56
|
-
overflowOptions = props.overflowOptions;
|
|
57
|
-
props = { ...props };
|
|
58
|
-
delete props.overflowOptions;
|
|
59
|
-
}
|
|
12
|
+
const Icon_js_1 = require('../Icon/Icon.js');
|
|
13
|
+
const TabsWrapper = React.forwardRef((props, ref) => {
|
|
60
14
|
const {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
focusActivationMode = 'auto',
|
|
15
|
+
className,
|
|
16
|
+
children,
|
|
17
|
+
orientation = 'horizontal',
|
|
65
18
|
type = 'default',
|
|
19
|
+
focusActivationMode = 'auto',
|
|
66
20
|
color = 'blue',
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
wrapperClassName,
|
|
71
|
-
children,
|
|
21
|
+
defaultValue,
|
|
22
|
+
value: activeValueProp,
|
|
23
|
+
onValueChange,
|
|
72
24
|
...rest
|
|
73
25
|
} = props;
|
|
26
|
+
const [activeValue, setActiveValue] = (0, index_js_1.useControlledState)(
|
|
27
|
+
defaultValue,
|
|
28
|
+
activeValueProp,
|
|
29
|
+
onValueChange,
|
|
30
|
+
);
|
|
31
|
+
const [stripeProperties, setStripeProperties] = React.useState({});
|
|
32
|
+
const [hasSublabel, setHasSublabel] = React.useState(false); // used for setting size
|
|
33
|
+
const idPrefix = (0, index_js_1.useId)();
|
|
34
|
+
return React.createElement(
|
|
35
|
+
index_js_1.Box,
|
|
36
|
+
{
|
|
37
|
+
className: (0, classnames_1.default)(
|
|
38
|
+
'iui-tabs-wrapper',
|
|
39
|
+
`iui-${orientation}`,
|
|
40
|
+
className,
|
|
41
|
+
),
|
|
42
|
+
...rest,
|
|
43
|
+
style: { ...stripeProperties, ...props?.style },
|
|
44
|
+
ref: ref,
|
|
45
|
+
},
|
|
46
|
+
React.createElement(
|
|
47
|
+
TabsContext.Provider,
|
|
48
|
+
{
|
|
49
|
+
value: {
|
|
50
|
+
orientation,
|
|
51
|
+
type,
|
|
52
|
+
activeValue,
|
|
53
|
+
setActiveValue,
|
|
54
|
+
setStripeProperties,
|
|
55
|
+
idPrefix,
|
|
56
|
+
focusActivationMode,
|
|
57
|
+
hasSublabel,
|
|
58
|
+
setHasSublabel,
|
|
59
|
+
color,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
children,
|
|
63
|
+
),
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
TabsWrapper.displayName = 'Tabs.Wrapper';
|
|
67
|
+
const TabList = React.forwardRef((props, ref) => {
|
|
68
|
+
const { className, children, ...rest } = props;
|
|
69
|
+
const { type, hasSublabel, color } = (0, index_js_1.useSafeContext)(
|
|
70
|
+
TabsContext,
|
|
71
|
+
);
|
|
74
72
|
const isClient = (0, index_js_1.useIsClient)();
|
|
75
73
|
const tablistRef = React.useRef(null);
|
|
76
74
|
const [tablistSizeRef, tabsWidth] = (0, index_js_1.useContainerWidth)(
|
|
77
75
|
type !== 'default',
|
|
78
76
|
);
|
|
79
|
-
const refs = (0, index_js_1.useMergedRefs)(tablistRef, tablistSizeRef);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
: 0,
|
|
77
|
+
const refs = (0, index_js_1.useMergedRefs)(ref, tablistRef, tablistSizeRef);
|
|
78
|
+
return React.createElement(
|
|
79
|
+
index_js_1.Box,
|
|
80
|
+
{
|
|
81
|
+
className: (0, classnames_1.default)(
|
|
82
|
+
'iui-tabs',
|
|
83
|
+
`iui-${type}`,
|
|
84
|
+
{
|
|
85
|
+
'iui-green': color === 'green',
|
|
86
|
+
'iui-animated': type !== 'default' && isClient,
|
|
87
|
+
'iui-not-animated': type !== 'default' && !isClient,
|
|
88
|
+
'iui-large': hasSublabel,
|
|
89
|
+
},
|
|
90
|
+
className,
|
|
91
|
+
),
|
|
92
|
+
role: 'tablist',
|
|
93
|
+
ref: refs,
|
|
94
|
+
...rest,
|
|
95
|
+
},
|
|
96
|
+
React.createElement(
|
|
97
|
+
TabListContext.Provider,
|
|
98
|
+
{
|
|
99
|
+
value: {
|
|
100
|
+
tabsWidth,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
children,
|
|
104
|
+
),
|
|
84
105
|
);
|
|
106
|
+
});
|
|
107
|
+
TabList.displayName = 'Tabs.TabList';
|
|
108
|
+
const Tab = React.forwardRef((props, forwardedRef) => {
|
|
109
|
+
const { className, children, value, label, ...rest } = props;
|
|
110
|
+
const {
|
|
111
|
+
orientation,
|
|
112
|
+
activeValue,
|
|
113
|
+
setActiveValue,
|
|
114
|
+
type,
|
|
115
|
+
setStripeProperties,
|
|
116
|
+
idPrefix,
|
|
117
|
+
focusActivationMode,
|
|
118
|
+
} = (0, index_js_1.useSafeContext)(TabsContext);
|
|
119
|
+
const { tabsWidth } = (0, index_js_1.useSafeContext)(TabListContext);
|
|
120
|
+
const tabRef = React.useRef();
|
|
121
|
+
const isActive = activeValue === value;
|
|
122
|
+
const isActiveRef = (0, index_js_1.useLatestRef)(isActive);
|
|
123
|
+
// Scroll to active tab only on initial render
|
|
85
124
|
(0, index_js_1.useIsomorphicLayoutEffect)(() => {
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const [stripeProperties, setStripeProperties] = React.useState({});
|
|
94
|
-
(0, index_js_1.useIsomorphicLayoutEffect)(() => {
|
|
95
|
-
if (type !== 'default' && tablistRef.current != undefined) {
|
|
96
|
-
const activeTab = tablistRef.current.children[currentActiveIndex];
|
|
97
|
-
const activeTabRect = activeTab.getBoundingClientRect();
|
|
98
|
-
setStripeProperties({
|
|
99
|
-
...(orientation === 'horizontal' && {
|
|
100
|
-
'--stripe-width': `${activeTabRect.width}px`,
|
|
101
|
-
'--stripe-left': `${activeTab.offsetLeft}px`,
|
|
102
|
-
}),
|
|
103
|
-
...(orientation === 'vertical' && {
|
|
104
|
-
'--stripe-height': `${activeTabRect.height}px`,
|
|
105
|
-
'--stripe-top': `${activeTab.offsetTop}px`,
|
|
106
|
-
}),
|
|
125
|
+
if (isActiveRef.current) {
|
|
126
|
+
tabRef.current?.parentElement?.scrollTo({
|
|
127
|
+
[orientation === 'horizontal' ? 'left' : 'top']:
|
|
128
|
+
tabRef.current?.[
|
|
129
|
+
orientation === 'horizontal' ? 'offsetLeft' : 'offsetTop'
|
|
130
|
+
] - 4,
|
|
131
|
+
behavior: 'instant', // not using 'smooth' to reduce layout shift on page load
|
|
107
132
|
});
|
|
108
133
|
}
|
|
109
|
-
}, [currentActiveIndex, type, orientation, tabsWidth]);
|
|
110
|
-
const [focusedIndex, setFocusedIndex] = React.useState();
|
|
111
|
-
React.useEffect(() => {
|
|
112
|
-
if (tablistRef.current && focusedIndex !== undefined) {
|
|
113
|
-
const tab = tablistRef.current.querySelectorAll(
|
|
114
|
-
`.${styles_js_1.default['iui-tab']}`,
|
|
115
|
-
)[focusedIndex];
|
|
116
|
-
tab?.focus();
|
|
117
|
-
}
|
|
118
|
-
}, [focusedIndex]);
|
|
119
|
-
const [hasSublabel, setHasSublabel] = React.useState(false); // used for setting size
|
|
120
|
-
(0, index_js_1.useIsomorphicLayoutEffect)(() => {
|
|
121
|
-
setHasSublabel(
|
|
122
|
-
type !== 'pill' && // pill tabs should never have sublabels
|
|
123
|
-
!!tablistRef.current?.querySelector(
|
|
124
|
-
`.${styles_js_1.default['iui-tab-description']}`,
|
|
125
|
-
),
|
|
126
|
-
);
|
|
127
|
-
}, [type]);
|
|
128
|
-
const enableHorizontalScroll = React.useCallback((e) => {
|
|
129
|
-
const ownerDoc = tablistRef.current;
|
|
130
|
-
if (ownerDoc === null) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
let scrollLeft = ownerDoc?.scrollLeft ?? 0;
|
|
134
|
-
if (e.deltaY > 0 || e.deltaX > 0) {
|
|
135
|
-
scrollLeft += 25;
|
|
136
|
-
} else if (e.deltaY < 0 || e.deltaX < 0) {
|
|
137
|
-
scrollLeft -= 25;
|
|
138
|
-
}
|
|
139
|
-
ownerDoc.scrollLeft = scrollLeft;
|
|
140
134
|
}, []);
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const isTabHidden = (activeTab, isVertical) => {
|
|
154
|
-
const ownerDoc = tablistRef.current;
|
|
155
|
-
if (ownerDoc === null) {
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const fadeBuffer = isVertical
|
|
159
|
-
? ownerDoc.offsetHeight * 0.05
|
|
160
|
-
: ownerDoc.offsetWidth * 0.05;
|
|
161
|
-
const visibleStart = isVertical ? ownerDoc.scrollTop : ownerDoc.scrollLeft;
|
|
162
|
-
const visibleEnd = isVertical
|
|
163
|
-
? ownerDoc.scrollTop + ownerDoc.offsetHeight
|
|
164
|
-
: ownerDoc.scrollLeft + ownerDoc.offsetWidth;
|
|
165
|
-
const tabStart = isVertical ? activeTab.offsetTop : activeTab.offsetLeft;
|
|
166
|
-
const tabEnd = isVertical
|
|
167
|
-
? activeTab.offsetTop + activeTab.offsetHeight
|
|
168
|
-
: activeTab.offsetLeft + activeTab.offsetWidth;
|
|
169
|
-
if (
|
|
170
|
-
tabStart > visibleStart + fadeBuffer &&
|
|
171
|
-
tabEnd < visibleEnd - fadeBuffer
|
|
172
|
-
) {
|
|
173
|
-
return 0; // tab is visible
|
|
174
|
-
} else if (tabStart < visibleStart + fadeBuffer) {
|
|
175
|
-
return -1; // tab is before visible section
|
|
176
|
-
} else {
|
|
177
|
-
return 1; // tab is after visible section
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
const easeInOutQuad = (time, beginning, change, duration) => {
|
|
181
|
-
if ((time /= duration / 2) < 1) {
|
|
182
|
-
return (change / 2) * time * time + beginning;
|
|
183
|
-
}
|
|
184
|
-
return (-change / 2) * (--time * (time - 2) - 1) + beginning;
|
|
135
|
+
const updateStripe = () => {
|
|
136
|
+
const currentTabRect = tabRef.current?.getBoundingClientRect();
|
|
137
|
+
setStripeProperties({
|
|
138
|
+
'--iui-tabs-stripe-size':
|
|
139
|
+
orientation === 'horizontal'
|
|
140
|
+
? `${currentTabRect?.width}px`
|
|
141
|
+
: `${currentTabRect?.height}px`,
|
|
142
|
+
'--iui-tabs-stripe-position':
|
|
143
|
+
orientation === 'horizontal'
|
|
144
|
+
? `${tabRef.current?.offsetLeft}px`
|
|
145
|
+
: `${tabRef.current?.offsetTop}px`,
|
|
146
|
+
});
|
|
185
147
|
};
|
|
186
|
-
|
|
187
|
-
(list, activeTab, duration, isVertical, tabPlacement) => {
|
|
188
|
-
const start = isVertical ? list.scrollTop : list.scrollLeft;
|
|
189
|
-
let change = 0;
|
|
190
|
-
let currentTime = 0;
|
|
191
|
-
const increment = 20;
|
|
192
|
-
const fadeBuffer = isVertical
|
|
193
|
-
? list.offsetHeight * 0.05
|
|
194
|
-
: list.offsetWidth * 0.05;
|
|
195
|
-
if (tabPlacement < 0) {
|
|
196
|
-
// if tab is before visible section
|
|
197
|
-
change = isVertical
|
|
198
|
-
? activeTab.offsetTop - list.scrollTop
|
|
199
|
-
: activeTab.offsetLeft - list.scrollLeft;
|
|
200
|
-
change -= fadeBuffer; // give some space so the active tab isn't covered by the fade
|
|
201
|
-
} else {
|
|
202
|
-
// tab is after visible section
|
|
203
|
-
change = isVertical
|
|
204
|
-
? activeTab.offsetTop -
|
|
205
|
-
(list.scrollTop + list.offsetHeight) +
|
|
206
|
-
activeTab.offsetHeight
|
|
207
|
-
: activeTab.offsetLeft -
|
|
208
|
-
(list.scrollLeft + list.offsetWidth) +
|
|
209
|
-
activeTab.offsetWidth;
|
|
210
|
-
change += fadeBuffer; // give some space so the active tab isn't covered by the fade
|
|
211
|
-
}
|
|
212
|
-
const animateScroll = () => {
|
|
213
|
-
currentTime += increment;
|
|
214
|
-
const val = easeInOutQuad(currentTime, start, change, duration);
|
|
215
|
-
if (isVertical) {
|
|
216
|
-
list.scrollTop = val;
|
|
217
|
-
} else {
|
|
218
|
-
list.scrollLeft = val;
|
|
219
|
-
}
|
|
220
|
-
if (currentTime < duration) {
|
|
221
|
-
setTimeout(animateScroll, increment);
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
animateScroll();
|
|
225
|
-
},
|
|
226
|
-
[],
|
|
227
|
-
);
|
|
228
|
-
// scroll to active tab if it is not visible with overflow
|
|
148
|
+
// CSS custom properties to place the active stripe
|
|
229
149
|
(0, index_js_1.useIsomorphicLayoutEffect)(() => {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
ownerDoc !== null &&
|
|
234
|
-
overflowOptions?.useOverflow &&
|
|
235
|
-
currentActiveIndex !== undefined
|
|
236
|
-
) {
|
|
237
|
-
const activeTab = ownerDoc.querySelectorAll(
|
|
238
|
-
`.${styles_js_1.default['iui-tab']}`,
|
|
239
|
-
)[currentActiveIndex];
|
|
240
|
-
const isVertical = orientation === 'vertical';
|
|
241
|
-
const tabPlacement = isTabHidden(activeTab, isVertical);
|
|
242
|
-
if (tabPlacement) {
|
|
243
|
-
scrollToTab(ownerDoc, activeTab, 100, isVertical, tabPlacement);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}, 50);
|
|
150
|
+
if (type !== 'default' && isActive) {
|
|
151
|
+
updateStripe();
|
|
152
|
+
}
|
|
247
153
|
}, [
|
|
248
|
-
|
|
249
|
-
currentActiveIndex,
|
|
250
|
-
focusedIndex,
|
|
154
|
+
type,
|
|
251
155
|
orientation,
|
|
252
|
-
|
|
156
|
+
isActive,
|
|
157
|
+
tabsWidth, // to fix visual artifact on initial render
|
|
253
158
|
]);
|
|
254
|
-
const [scrollingPlacement, setScrollingPlacement] = React.useState(undefined);
|
|
255
|
-
const determineScrollingPlacement = React.useCallback(() => {
|
|
256
|
-
const ownerDoc = tablistRef.current;
|
|
257
|
-
if (ownerDoc === null) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
260
|
-
const isVertical = orientation === 'vertical';
|
|
261
|
-
const visibleStart = isVertical ? ownerDoc.scrollTop : ownerDoc.scrollLeft;
|
|
262
|
-
const visibleEnd = isVertical
|
|
263
|
-
? ownerDoc.scrollTop + ownerDoc.offsetHeight
|
|
264
|
-
: ownerDoc.scrollLeft + ownerDoc.offsetWidth;
|
|
265
|
-
const totalTabsSpace = isVertical
|
|
266
|
-
? ownerDoc.scrollHeight
|
|
267
|
-
: ownerDoc.scrollWidth;
|
|
268
|
-
if (
|
|
269
|
-
Math.abs(visibleStart - 0) < 1 &&
|
|
270
|
-
Math.abs(visibleEnd - totalTabsSpace) < 1
|
|
271
|
-
) {
|
|
272
|
-
setScrollingPlacement(undefined);
|
|
273
|
-
} else if (Math.abs(visibleStart - 0) < 1) {
|
|
274
|
-
setScrollingPlacement('start');
|
|
275
|
-
} else if (Math.abs(visibleEnd - totalTabsSpace) < 1) {
|
|
276
|
-
setScrollingPlacement('end');
|
|
277
|
-
} else {
|
|
278
|
-
setScrollingPlacement('center');
|
|
279
|
-
}
|
|
280
|
-
}, [orientation, setScrollingPlacement]);
|
|
281
|
-
// apply correct mask when tabs list is resized
|
|
282
|
-
const [resizeRef] = (0, index_js_1.useResizeObserver)(
|
|
283
|
-
determineScrollingPlacement,
|
|
284
|
-
);
|
|
285
|
-
resizeRef(tablistRef?.current);
|
|
286
|
-
// check if overflow tabs are scrolled to far edges
|
|
287
|
-
React.useEffect(() => {
|
|
288
|
-
const ownerDoc = tablistRef.current;
|
|
289
|
-
if (ownerDoc === null) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
if (!overflowOptions?.useOverflow) {
|
|
293
|
-
ownerDoc.removeEventListener('scroll', determineScrollingPlacement);
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
ownerDoc.addEventListener('scroll', determineScrollingPlacement);
|
|
297
|
-
}, [overflowOptions?.useOverflow, determineScrollingPlacement]);
|
|
298
|
-
const onTabClick = React.useCallback(
|
|
299
|
-
(index) => {
|
|
300
|
-
if (onTabSelected) {
|
|
301
|
-
onTabSelected(index);
|
|
302
|
-
}
|
|
303
|
-
setCurrentActiveIndex(index);
|
|
304
|
-
},
|
|
305
|
-
[onTabSelected],
|
|
306
|
-
);
|
|
307
159
|
const onKeyDown = (event) => {
|
|
308
|
-
// alt + arrow keys are used by browser / assistive technologies
|
|
309
160
|
if (event.altKey) {
|
|
310
161
|
return;
|
|
311
162
|
}
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const focusTab = (delta = +1) => {
|
|
319
|
-
do {
|
|
320
|
-
newIndex = (newIndex + delta + labels.length) % labels.length;
|
|
321
|
-
} while (isTabDisabled(newIndex) && newIndex !== focusedIndex);
|
|
322
|
-
setFocusedIndex(newIndex);
|
|
323
|
-
focusActivationMode === 'auto' && onTabClick(newIndex);
|
|
324
|
-
};
|
|
163
|
+
const allTabs = Array.from(
|
|
164
|
+
event.currentTarget.parentElement?.children ?? [],
|
|
165
|
+
);
|
|
166
|
+
const nextTab = tabRef.current?.nextElementSibling ?? allTabs.at(0);
|
|
167
|
+
const previousTab =
|
|
168
|
+
tabRef.current?.previousElementSibling ?? allTabs.at(-1);
|
|
325
169
|
switch (event.key) {
|
|
326
170
|
case 'ArrowDown': {
|
|
327
171
|
if (orientation === 'vertical') {
|
|
328
|
-
|
|
172
|
+
nextTab?.focus();
|
|
329
173
|
event.preventDefault();
|
|
330
174
|
}
|
|
331
175
|
break;
|
|
332
176
|
}
|
|
333
177
|
case 'ArrowRight': {
|
|
334
178
|
if (orientation === 'horizontal') {
|
|
335
|
-
|
|
179
|
+
nextTab?.focus();
|
|
336
180
|
event.preventDefault();
|
|
337
181
|
}
|
|
338
182
|
break;
|
|
339
183
|
}
|
|
340
184
|
case 'ArrowUp': {
|
|
341
185
|
if (orientation === 'vertical') {
|
|
342
|
-
|
|
186
|
+
previousTab?.focus();
|
|
343
187
|
event.preventDefault();
|
|
344
188
|
}
|
|
345
189
|
break;
|
|
346
190
|
}
|
|
347
191
|
case 'ArrowLeft': {
|
|
348
192
|
if (orientation === 'horizontal') {
|
|
349
|
-
|
|
193
|
+
previousTab?.focus();
|
|
350
194
|
event.preventDefault();
|
|
351
195
|
}
|
|
352
196
|
break;
|
|
353
197
|
}
|
|
354
|
-
case 'Enter':
|
|
355
|
-
case ' ':
|
|
356
|
-
case 'Spacebar': {
|
|
357
|
-
event.preventDefault();
|
|
358
|
-
if (focusActivationMode === 'manual' && focusedIndex !== undefined) {
|
|
359
|
-
onTabClick(focusedIndex);
|
|
360
|
-
}
|
|
361
|
-
break;
|
|
362
|
-
}
|
|
363
198
|
default:
|
|
364
199
|
break;
|
|
365
200
|
}
|
|
366
201
|
};
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
202
|
+
// use first tab as active if no `value` passed.
|
|
203
|
+
const setInitialActiveRef = React.useCallback(
|
|
204
|
+
(element) => {
|
|
205
|
+
if (activeValue !== undefined) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (element?.matches(':first-of-type')) {
|
|
209
|
+
setActiveValue(value);
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
[activeValue, setActiveValue, value],
|
|
213
|
+
);
|
|
214
|
+
return React.createElement(
|
|
215
|
+
index_js_1.ButtonBase,
|
|
216
|
+
{
|
|
217
|
+
className: (0, classnames_1.default)('iui-tab', className),
|
|
218
|
+
role: 'tab',
|
|
219
|
+
tabIndex: isActive ? 0 : -1,
|
|
220
|
+
'aria-selected': isActive,
|
|
221
|
+
'aria-controls': `${idPrefix}-panel-${value}`,
|
|
222
|
+
ref: (0, index_js_1.useMergedRefs)(
|
|
223
|
+
tabRef,
|
|
224
|
+
forwardedRef,
|
|
225
|
+
setInitialActiveRef,
|
|
226
|
+
),
|
|
227
|
+
...rest,
|
|
228
|
+
id: `${idPrefix}-tab-${value}`,
|
|
229
|
+
onClick: (0, index_js_1.mergeEventHandlers)(props.onClick, () =>
|
|
230
|
+
setActiveValue(value),
|
|
231
|
+
),
|
|
232
|
+
onKeyDown: (0, index_js_1.mergeEventHandlers)(props.onKeyDown, onKeyDown),
|
|
233
|
+
onFocus: (0, index_js_1.mergeEventHandlers)(props.onFocus, () => {
|
|
234
|
+
tabRef.current?.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
|
235
|
+
if (focusActivationMode === 'auto' && !props.disabled) {
|
|
236
|
+
setActiveValue(value);
|
|
237
|
+
}
|
|
238
|
+
}),
|
|
396
239
|
},
|
|
397
|
-
|
|
240
|
+
label ? React.createElement(exports.Tabs.TabLabel, null, label) : children,
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
Tab.displayName = 'Tabs.Tab';
|
|
244
|
+
// ----------------------------------------------------------------------------
|
|
245
|
+
// Tabs.TabIcon component
|
|
246
|
+
const TabIcon = React.forwardRef((props, ref) => {
|
|
247
|
+
return React.createElement(Icon_js_1.Icon, {
|
|
248
|
+
...props,
|
|
249
|
+
className: (0, classnames_1.default)('iui-tab-icon', props?.className),
|
|
250
|
+
ref: ref,
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
TabIcon.displayName = 'Tabs.TabIcon';
|
|
254
|
+
// ----------------------------------------------------------------------------
|
|
255
|
+
// Tabs.TabLabel component
|
|
256
|
+
const TabLabel = index_js_1.polymorphic.span('iui-tab-label');
|
|
257
|
+
TabLabel.displayName = 'Tabs.TabLabel';
|
|
258
|
+
// ----------------------------------------------------------------------------
|
|
259
|
+
// Tabs.TabDescription component
|
|
260
|
+
const TabDescription = React.forwardRef((props, ref) => {
|
|
261
|
+
const { className, children, ...rest } = props;
|
|
262
|
+
const { hasSublabel, setHasSublabel } = (0, index_js_1.useSafeContext)(
|
|
263
|
+
TabsContext,
|
|
398
264
|
);
|
|
265
|
+
(0, index_js_1.useIsomorphicLayoutEffect)(() => {
|
|
266
|
+
if (!hasSublabel) {
|
|
267
|
+
setHasSublabel(true);
|
|
268
|
+
}
|
|
269
|
+
}, [hasSublabel, setHasSublabel]);
|
|
399
270
|
return React.createElement(
|
|
400
271
|
index_js_1.Box,
|
|
401
272
|
{
|
|
273
|
+
as: 'span',
|
|
274
|
+
className: (0, classnames_1.default)('iui-tab-description', className),
|
|
275
|
+
ref: ref,
|
|
276
|
+
...rest,
|
|
277
|
+
},
|
|
278
|
+
children,
|
|
279
|
+
);
|
|
280
|
+
});
|
|
281
|
+
TabDescription.displayName = 'Tabs.TabDescription';
|
|
282
|
+
const TabsActions = React.forwardRef((props, ref) => {
|
|
283
|
+
const { wrapperProps, className, children, ...rest } = props;
|
|
284
|
+
return React.createElement(
|
|
285
|
+
index_js_1.Box,
|
|
286
|
+
{
|
|
287
|
+
...wrapperProps,
|
|
402
288
|
className: (0, classnames_1.default)(
|
|
403
|
-
'iui-tabs-wrapper',
|
|
404
|
-
|
|
405
|
-
wrapperClassName,
|
|
289
|
+
'iui-tabs-actions-wrapper',
|
|
290
|
+
wrapperProps?.className,
|
|
406
291
|
),
|
|
407
|
-
style: stripeProperties,
|
|
408
292
|
},
|
|
409
293
|
React.createElement(
|
|
410
294
|
index_js_1.Box,
|
|
411
295
|
{
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
'iui-tabs',
|
|
415
|
-
`iui-${type}`,
|
|
416
|
-
{
|
|
417
|
-
'iui-green': color === 'green',
|
|
418
|
-
'iui-animated': type !== 'default' && isClient,
|
|
419
|
-
'iui-not-animated': type !== 'default' && !isClient,
|
|
420
|
-
'iui-large': hasSublabel,
|
|
421
|
-
},
|
|
422
|
-
tabsClassName,
|
|
423
|
-
),
|
|
424
|
-
'data-iui-overflow': overflowOptions?.useOverflow,
|
|
425
|
-
'data-iui-scroll-placement': scrollingPlacement,
|
|
426
|
-
role: 'tablist',
|
|
427
|
-
ref: refs,
|
|
428
|
-
onKeyDown: onKeyDown,
|
|
296
|
+
className: (0, classnames_1.default)('iui-tabs-actions', className),
|
|
297
|
+
ref: ref,
|
|
429
298
|
...rest,
|
|
430
299
|
},
|
|
431
|
-
|
|
300
|
+
children,
|
|
432
301
|
),
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
),
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
TabsActions.displayName = 'Tabs.Actions';
|
|
305
|
+
const TabsPanel = React.forwardRef((props, ref) => {
|
|
306
|
+
const { value, className, children, ...rest } = props;
|
|
307
|
+
const { activeValue, idPrefix } = (0, index_js_1.useSafeContext)(TabsContext);
|
|
308
|
+
return React.createElement(
|
|
309
|
+
index_js_1.Box,
|
|
310
|
+
{
|
|
311
|
+
className: (0, classnames_1.default)('iui-tabs-content', className),
|
|
312
|
+
'aria-labelledby': `${idPrefix}-tab-${value}`,
|
|
313
|
+
role: 'tabpanel',
|
|
314
|
+
hidden: activeValue !== value ? true : undefined,
|
|
315
|
+
ref: ref,
|
|
316
|
+
...rest,
|
|
317
|
+
id: `${idPrefix}-panel-${value}`,
|
|
318
|
+
},
|
|
319
|
+
children,
|
|
320
|
+
);
|
|
321
|
+
});
|
|
322
|
+
TabsPanel.displayName = 'Tabs.Panel';
|
|
323
|
+
const LegacyTabsComponent = React.forwardRef((props, forwardedRef) => {
|
|
324
|
+
let actions;
|
|
325
|
+
if (props.type !== 'pill' && props.actions) {
|
|
326
|
+
actions = props.actions;
|
|
327
|
+
props = { ...props };
|
|
328
|
+
delete props.actions;
|
|
329
|
+
}
|
|
330
|
+
const {
|
|
331
|
+
labels,
|
|
332
|
+
onTabSelected,
|
|
333
|
+
focusActivationMode,
|
|
334
|
+
color,
|
|
335
|
+
activeIndex: activeIndexProp,
|
|
336
|
+
tabsClassName,
|
|
337
|
+
contentClassName,
|
|
338
|
+
wrapperClassName,
|
|
339
|
+
children,
|
|
340
|
+
...rest
|
|
341
|
+
} = props;
|
|
342
|
+
const [activeIndex, setActiveIndex] = (0, index_js_1.useControlledState)(
|
|
343
|
+
0,
|
|
344
|
+
activeIndexProp,
|
|
345
|
+
onTabSelected,
|
|
346
|
+
);
|
|
347
|
+
return React.createElement(
|
|
348
|
+
TabsWrapper,
|
|
349
|
+
{
|
|
350
|
+
className: wrapperClassName,
|
|
351
|
+
focusActivationMode: focusActivationMode,
|
|
352
|
+
color: color,
|
|
353
|
+
value: `${activeIndex}`,
|
|
354
|
+
onValueChange: (value) => setActiveIndex(Number(value)),
|
|
355
|
+
...rest,
|
|
356
|
+
},
|
|
357
|
+
React.createElement(
|
|
358
|
+
TabList,
|
|
359
|
+
{ className: tabsClassName, ref: forwardedRef },
|
|
360
|
+
labels.map((label, index) => {
|
|
361
|
+
const tabValue = `${index}`;
|
|
362
|
+
return React.isValidElement(label)
|
|
363
|
+
? React.cloneElement(label, {
|
|
364
|
+
value: tabValue,
|
|
365
|
+
})
|
|
366
|
+
: React.createElement(LegacyTab, {
|
|
367
|
+
key: index,
|
|
368
|
+
value: tabValue,
|
|
369
|
+
label: label,
|
|
370
|
+
});
|
|
371
|
+
}),
|
|
372
|
+
),
|
|
373
|
+
actions && React.createElement(TabsActions, null, actions),
|
|
443
374
|
children &&
|
|
444
375
|
React.createElement(
|
|
445
|
-
|
|
446
|
-
{
|
|
447
|
-
className: (0, classnames_1.default)(
|
|
448
|
-
'iui-tabs-content',
|
|
449
|
-
contentClassName,
|
|
450
|
-
),
|
|
451
|
-
role: 'tabpanel',
|
|
452
|
-
},
|
|
376
|
+
TabsPanel,
|
|
377
|
+
{ value: `${activeIndex}`, className: contentClassName },
|
|
453
378
|
children,
|
|
454
379
|
),
|
|
455
380
|
);
|
|
456
|
-
};
|
|
457
|
-
|
|
381
|
+
});
|
|
382
|
+
LegacyTabsComponent.displayName = 'Tabs';
|
|
383
|
+
/**
|
|
384
|
+
* Legacy Tab component.
|
|
385
|
+
* For full functionality use composition API.
|
|
386
|
+
*
|
|
387
|
+
* Individual tab component to be used in the `labels` prop of `Tabs`.
|
|
388
|
+
* @example
|
|
389
|
+
* const tabs = [
|
|
390
|
+
* <Tab label='Label 1' sublabel='Description 1' />,
|
|
391
|
+
* <Tab label='Label 2' startIcon={<SvgPlaceholder />} />,
|
|
392
|
+
* ];
|
|
393
|
+
*/
|
|
394
|
+
const LegacyTab = React.forwardRef((props, forwardedRef) => {
|
|
395
|
+
const { label, sublabel, startIcon, children, value, ...rest } = props;
|
|
396
|
+
return React.createElement(
|
|
397
|
+
React.Fragment,
|
|
398
|
+
null,
|
|
399
|
+
React.createElement(
|
|
400
|
+
Tab,
|
|
401
|
+
{ ...rest, value: value, ref: forwardedRef },
|
|
402
|
+
startIcon && React.createElement(TabIcon, null, startIcon),
|
|
403
|
+
React.createElement(TabLabel, null, label),
|
|
404
|
+
sublabel && React.createElement(TabDescription, null, sublabel),
|
|
405
|
+
children,
|
|
406
|
+
),
|
|
407
|
+
);
|
|
408
|
+
});
|
|
409
|
+
exports.Tab = LegacyTab;
|
|
410
|
+
/**
|
|
411
|
+
* Tabs organize and allow navigation between groups of content that are related and at the same level of hierarchy.
|
|
412
|
+
* `Tabs.Tab` and `Tabs.Panel` can be associated with each other by passing them the same `value`.
|
|
413
|
+
* @example
|
|
414
|
+
* <Tabs.Wrapper>
|
|
415
|
+
* <Tabs.TabList>
|
|
416
|
+
* <Tabs.Tab value='tab1' label='Label 1' />
|
|
417
|
+
* <Tabs.Tab value='tab2' label='Label 2' />
|
|
418
|
+
* <Tabs.Tab value='tab3' label='Label 3' />
|
|
419
|
+
* </Tabs.TabList>
|
|
420
|
+
* <Tabs.ActionsWrapper>
|
|
421
|
+
* <Tabs.Actions>
|
|
422
|
+
* <Button>Sample Button</Button>
|
|
423
|
+
* </Tabs.Actions>
|
|
424
|
+
* </Tabs.ActionsWrapper>
|
|
425
|
+
* <Tabs.Panel value='tab1'>Content 1</Tabs.Panel>
|
|
426
|
+
* <Tabs.Panel value='tab2'>Content 2</Tabs.Panel>
|
|
427
|
+
* <Tabs.Panel value='tab3'>Content 3</Tabs.Panel>
|
|
428
|
+
* </Tabs.Wrapper>
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* <Tabs orientation='vertical'/>
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* <Tabs.Wrapper focusActivationMode='manual'>
|
|
435
|
+
* <Tabs.Tab value='sample'>
|
|
436
|
+
* <Tabs.TabIcon>
|
|
437
|
+
* <SvgPlaceholder />
|
|
438
|
+
* </Tabs.TabIcon>
|
|
439
|
+
* <Tabs.TabLabel>Sample Label</Tabs.TabLabel>
|
|
440
|
+
* <Tabs.TabDescription>Sample Description</Tabs.TabDescription>
|
|
441
|
+
* </Tabs.Tab>
|
|
442
|
+
* </Tabs.Wrapper>
|
|
443
|
+
*/
|
|
444
|
+
exports.Tabs = Object.assign(LegacyTabsComponent, {
|
|
445
|
+
/**
|
|
446
|
+
* A wrapper component for Tabs
|
|
447
|
+
*/
|
|
448
|
+
Wrapper: TabsWrapper,
|
|
449
|
+
/**
|
|
450
|
+
* Tablist subcomponent which contains all of the tab subcomponents.
|
|
451
|
+
* @example
|
|
452
|
+
* <Tabs.TabList>
|
|
453
|
+
* <Tabs.Tab value='tab1' label='Label 1' />
|
|
454
|
+
* <Tabs.Tab value='tab2' label='Label 2' />
|
|
455
|
+
* <Tabs.Tab value='tab3' label='Label 3' />
|
|
456
|
+
* </Tabs.TabList>
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* <Tabs.TabList>
|
|
460
|
+
* <Tabs.Tab value='tab1' label='Green Tab' />
|
|
461
|
+
* </Tabs.TabList>
|
|
462
|
+
*
|
|
463
|
+
* @example
|
|
464
|
+
* <Tabs.TabList focusActivationMode='manual'>
|
|
465
|
+
* <Tabs.Tab value='tab1' label='Manual Focus Tab' />
|
|
466
|
+
* </Tabs.TabList>
|
|
467
|
+
*/
|
|
468
|
+
TabList: TabList,
|
|
469
|
+
/**
|
|
470
|
+
* Tab subcomponent which is used for each of the tabs.
|
|
471
|
+
* @example
|
|
472
|
+
* <Tabs.Tab value='tab1' label='Label 1' />
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* <Tabs.Tab value='sample'>
|
|
476
|
+
* <Tabs.TabIcon>
|
|
477
|
+
* <SvgPlaceholder />
|
|
478
|
+
* </Tabs.TabIcon>
|
|
479
|
+
* <Tabs.TabLabel>Sample Label</Tabs.TabLabel>
|
|
480
|
+
* <Tabs.TabDescription>Sample Description</Tabs.TabDescription>
|
|
481
|
+
* </Tabs.Tab>
|
|
482
|
+
*
|
|
483
|
+
*/
|
|
484
|
+
Tab: Tab,
|
|
485
|
+
/**
|
|
486
|
+
* Tab icon subcomponent which places an icon on the left side of the tab.
|
|
487
|
+
*/
|
|
488
|
+
TabIcon: TabIcon,
|
|
489
|
+
/**
|
|
490
|
+
* Tab label subcomponent which holds the tab's label.
|
|
491
|
+
*/
|
|
492
|
+
TabLabel: TabLabel,
|
|
493
|
+
/**
|
|
494
|
+
* Tab description subcomponent which places a description under the tab label.
|
|
495
|
+
*/
|
|
496
|
+
TabDescription: TabDescription,
|
|
497
|
+
/**
|
|
498
|
+
* Tab actions subcomponent which contains action buttons that are placed at the end of the tabs.
|
|
499
|
+
*/
|
|
500
|
+
Actions: TabsActions,
|
|
501
|
+
/**
|
|
502
|
+
* Tab panel subcomponent which contains the tab's content.
|
|
503
|
+
* @example
|
|
504
|
+
* <Tabs.Panel value='tab1'>
|
|
505
|
+
* Sample Panel
|
|
506
|
+
* </Tabs.Panel>
|
|
507
|
+
*/
|
|
508
|
+
Panel: TabsPanel,
|
|
509
|
+
});
|
|
510
|
+
const TabsContext = React.createContext(undefined);
|
|
511
|
+
const TabListContext = React.createContext(undefined);
|
|
458
512
|
exports.default = exports.Tabs;
|