Skip to content

Commit afd0bc4

Browse files
authored
Merge pull request #479 from mashmatrix/support-slds-2-tabs
Update `Tabs` for SLDS2
2 parents 5d62cb0 + 2ad814c commit afd0bc4

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

src/scripts/Tabs.tsx

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import React, {
66
ReactNode,
77
Ref,
88
createContext,
9+
useId,
910
useContext,
1011
useMemo,
1112
useRef,
@@ -45,8 +46,21 @@ const TabsActiveKeyContext = createContext<TabKey | undefined>(undefined);
4546
const TabsContext = createContext<{
4647
type: TabType;
4748
activeTabRef?: Ref<HTMLAnchorElement>;
49+
tabIdPrefix?: string;
50+
tabItemIdPrefix?: string;
4851
}>({ type: 'default' });
4952

53+
/**
54+
* Custom hook to generate unique tab IDs
55+
*/
56+
const useTabIds = (eventKey?: TabKey) => {
57+
const { tabIdPrefix, tabItemIdPrefix } = useContext(TabsContext);
58+
const tabIndex = eventKey ? String(eventKey) : '0';
59+
const tabId = `${tabIdPrefix}-${tabIndex}`;
60+
const tabItemId = `${tabItemIdPrefix}-${tabIndex}`;
61+
return { tabId, tabItemId };
62+
};
63+
5064
/**
5165
*
5266
*/
@@ -59,9 +73,10 @@ export type TabContentProps = {
5973
*/
6074
const TabContent: FC<TabContentProps> = (props) => {
6175
const { className, active, children, ...rprops } = props;
76+
const { type } = useContext(TabsContext);
6277
const tabClassNames = classnames(
6378
className,
64-
'slds-tabs__content',
79+
`slds-tabs_${type}__content`,
6580
`slds-${active ? 'show' : 'hide'}`
6681
);
6782
return (
@@ -143,6 +158,7 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
143158
const { type, activeTabRef } = useContext(TabsContext);
144159
const activeKey = useContext(TabsActiveKeyContext);
145160
const { onTabClick, onTabKeyDown } = useContext(TabsHandlersContext);
161+
const { tabId, tabItemId } = useTabIds(eventKey);
146162
let { menuItems } = props;
147163
menuItems = menu
148164
? React.Children.toArray(
@@ -152,9 +168,9 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
152168
const menuProps = (menu?.props as unknown) ?? {};
153169
const isActive = eventKey === activeKey;
154170
const tabItemClassName = classnames(
155-
{ 'slds-tabs__item': !!menuItems },
171+
'react-slds-tab-item',
156172
`slds-tabs_${type}__item`,
157-
{ 'slds-active': isActive },
173+
{ 'slds-is-active': isActive },
158174
{ 'react-slds-tab-with-menu': menu || menuItems }
159175
);
160176
const tabLinkClassName = `slds-tabs_${type}__link`;
@@ -173,19 +189,21 @@ const TabItem = <RendererProps extends TabItemRendererProps>(
173189
onTabKeyDown,
174190
} as RendererProps;
175191
return (
176-
<li className={tabItemClassName} role='presentation'>
192+
<li className={tabItemClassName} title={title} role='presentation'>
177193
<TabItemRenderer {...itemRendererProps}>
178194
<span
179195
className={`react-slds-tab-item-content ${
180196
tooltip ? 'react-slds-tooltip-enabled' : ''
181197
}`}
182198
>
183199
<a
200+
id={tabItemId}
184201
className={tabLinkClassName}
185202
role='tab'
186203
ref={isActive ? activeTabRef : undefined}
187204
tabIndex={isActive ? 0 : -1}
188205
aria-selected={isActive}
206+
aria-controls={tabId}
189207
onClick={
190208
eventKey != null ? () => onTabClick?.(eventKey) : undefined
191209
}
@@ -244,10 +262,13 @@ export const Tab = <
244262
) => {
245263
const { className, eventKey, children } = props;
246264
const activeKey = useContext(TabsActiveKeyContext);
265+
const { tabId, tabItemId } = useTabIds(eventKey);
247266
return (
248267
<TabContent
268+
id={tabId}
249269
className={className}
250270
active={eventKey != null && eventKey === activeKey}
271+
aria-labelledby={tabItemId}
251272
>
252273
{children}
253274
</TabContent>
@@ -273,34 +294,34 @@ function useInitComponentStyle() {
273294
useEffect(() => {
274295
registerStyle('tab-menu', [
275296
[
276-
'.slds-tabs__item.react-slds-tab-with-menu',
297+
'.react-slds-tab-item.react-slds-tab-with-menu',
277298
'{ position: relative !important; overflow: visible !important; }',
278299
],
279300
[
280-
'.slds-tabs__item.react-slds-tab-with-menu > .react-slds-tab-item-content',
301+
'.react-slds-tab-item.react-slds-tab-with-menu > .react-slds-tab-item-content',
281302
'{ overflow: hidden }',
282303
],
283304
[
284-
'.slds-tabs__item.react-slds-tab-with-menu > .react-slds-tab-item-content > a',
305+
'.react-slds-tab-item.react-slds-tab-with-menu > .react-slds-tab-item-content > a',
285306
'{ padding-right: 2rem; }',
286307
],
287308
[
288-
'.slds-tabs__item.react-slds-tab-with-menu > .react-slds-tab-item-content.react-slds-tooltip-enabled > a',
309+
'.react-slds-tab-item.react-slds-tab-with-menu > .react-slds-tab-item-content.react-slds-tooltip-enabled > a',
289310
'{ padding-right: 3.5rem; }',
290311
],
291312
['.react-slds-tab-menu', '{ position: absolute; top: 0; right: 0; }'],
292313
[
293-
'.slds-tabs__item.react-slds-tab-with-menu .react-slds-tab-item-content .react-slds-tooltip-content',
314+
'.react-slds-tab-item.react-slds-tab-with-menu .react-slds-tab-item-content .react-slds-tooltip-content',
294315
'{ position: absolute; top: 0.6rem; right: 2.25rem; }',
295316
],
296317
[
297318
'.react-slds-tab-menu button',
298319
'{ height: 2.5rem; line-height: 2rem; width: 2rem; visibility: hidden; justify-content: center }',
299320
],
300321
[
301-
'.slds-tabs__item.slds-active .react-slds-tab-menu button',
302-
'.slds-tabs__item:hover .react-slds-tab-menu button',
303-
'.slds-tabs__item .react-slds-tab-menu button:focus',
322+
'.react-slds-tab-item.slds-is-active .react-slds-tab-menu button',
323+
'.react-slds-tab-item:hover .react-slds-tab-menu button',
324+
'.react-slds-tab-item .react-slds-tab-menu button:focus',
304325
'{ visibility: visible }',
305326
],
306327
]);
@@ -369,7 +390,13 @@ export const Tabs: FC<TabsProps> = (props) => {
369390
}
370391
}, [focusTab]);
371392

372-
const tabCtx = useMemo(() => ({ type, activeTabRef }), [type]);
393+
const tabIdPrefix = useId();
394+
const tabItemIdPrefix = useId();
395+
const tabCtx = useMemo(
396+
() => ({ type, activeTabRef, tabIdPrefix, tabItemIdPrefix }),
397+
[type, tabIdPrefix, tabItemIdPrefix]
398+
);
399+
373400
const handlers = useMemo(
374401
() => ({ onTabClick, onTabKeyDown }),
375402
[onTabClick, onTabKeyDown]

0 commit comments

Comments
 (0)