Skip to content

Commit 1378794

Browse files
Revert "fix: tab: added a prop to enable standard key navigation for tabs com…" (#1026)
This reverts commit 7934881. Co-authored-by: ypatadia-eightfold <ypatadia@eightfold.ai>
1 parent 7693ca2 commit 1378794

File tree

10 files changed

+14
-1055
lines changed

10 files changed

+14
-1055
lines changed

src/components/Dialog/BaseDialog/BaseDialog.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,8 @@ export const BaseDialog: FC<BaseDialogProps> = React.forwardRef(
155155
<span
156156
id={labelId}
157157
{...(header && {
158-
role: 'heading',
159-
'aria-level': headingLevel,
158+
role: "heading",
159+
"aria-level": headingLevel
160160
})}
161161
>
162162
{headerButtonProps && (

src/components/Dialog/Dialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export const Dialog: FC<DialogProps> = React.forwardRef(
4242
headerButtonProps,
4343
headerClassNames,
4444
headerIcon,
45-
headingLevel = 1,
45+
headingLevel=1,
4646
height,
4747
locale = enUS,
4848
okButtonProps,

src/components/Tabs/Tab/Tab.tsx

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import React, { FC, Ref, useEffect, useRef } from 'react';
3+
import React, { FC, Ref } from 'react';
44
import { mergeClasses } from '../../../shared/utilities';
55
import { TabIconAlign, TabProps, TabSize, TabVariant } from '../Tabs.types';
66
import { useTabs } from '../Tabs.context';
@@ -12,7 +12,6 @@ import { Badge } from '../../Badge';
1212
import { Loader } from '../../Loader';
1313
import { useCanvasDirection } from '../../../hooks/useCanvasDirection';
1414

15-
import { useMergedRefs } from '../../../hooks/useMergedRefs';
1615
import styles from '../tabs.module.scss';
1716

1817
export const Tab: FC<TabProps> = React.forwardRef(
@@ -26,15 +25,11 @@ export const Tab: FC<TabProps> = React.forwardRef(
2625
label,
2726
loading,
2827
value,
29-
ariaControls,
30-
index = 0,
3128
...rest
3229
},
3330
ref: Ref<HTMLButtonElement>
3431
) => {
3532
const htmlDir: string = useCanvasDirection();
36-
const tabRef = useRef(null);
37-
const combinedRef = useMergedRefs(ref, tabRef);
3833

3934
const {
4035
alignIcon,
@@ -43,10 +38,6 @@ export const Tab: FC<TabProps> = React.forwardRef(
4338
currentActiveTab,
4439
size,
4540
variant,
46-
enableArrowNav,
47-
handleKeyDown,
48-
registerTab,
49-
focusedTabIndex,
5041
theme,
5142
} = useTabs();
5243

@@ -72,12 +63,6 @@ export const Tab: FC<TabProps> = React.forwardRef(
7263
[TabSize.XSmall, IconSize.Small],
7364
]);
7465

75-
useEffect(() => {
76-
if (registerTab) {
77-
registerTab(tabRef.current, index);
78-
}
79-
}, [registerTab, index]);
80-
8166
const getIcon = (): JSX.Element =>
8267
// TODO: Once sizes are implemented for other variants, use the mapping.
8368
// For now, a ternary determines if mapping vs using the default icon size (medium).
@@ -121,41 +106,16 @@ export const Tab: FC<TabProps> = React.forwardRef(
121106
const getLoader = (): JSX.Element =>
122107
loading && <Loader classNames={styles.loader} />;
123108

124-
const handleTabKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {
125-
if (enableArrowNav && index !== undefined) {
126-
handleKeyDown?.(e, index);
127-
}
128-
};
129-
130-
const match = currentActiveTab?.match(/\d+/);
131-
const currentActiveTabIndex = match ? Number(match[0]) - 1 : -1;
132-
133-
const getTabIndex = () => {
134-
if (
135-
currentActiveTabIndex !== undefined &&
136-
currentActiveTabIndex !== null &&
137-
index === currentActiveTabIndex
138-
) {
139-
return 0;
140-
}
141-
return -1;
142-
};
143-
144109
return (
145110
<button
146111
{...rest}
147-
aria-controls={ariaControls}
148-
ref={combinedRef}
112+
ref={ref}
149113
className={tabClassNames}
150114
aria-label={ariaLabel}
151115
aria-selected={isActive}
152116
role="tab"
153117
disabled={disabled}
154118
onClick={(e) => onTabClick(value, e)}
155-
onKeyDown={handleTabKeyDown}
156-
tabIndex={getTabIndex()}
157-
data-index={index}
158-
data-value={value}
159119
>
160120
{alignIcon === TabIconAlign.Start && getIcon()}
161121
{getLabel()}

src/components/Tabs/Tabs.context.tsx

Lines changed: 5 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
import React, {
2-
createContext,
3-
useCallback,
4-
useEffect,
5-
useState,
6-
useRef,
7-
} from 'react';
1+
import React, { createContext, useEffect, useState } from 'react';
82
import {
93
TabsContextProps,
104
ITabsContext,
@@ -35,188 +29,17 @@ const TabsProvider = ({
3529
themeContainerId,
3630
statgrouptheme,
3731
value,
38-
disabledTabIndexes = [],
39-
enableArrowNav = true,
4032
variant = TabVariant.default,
4133
}: TabsContextProps) => {
42-
const [currentActiveTab, setCurrentActiveTab] = useState(value);
43-
const [focusedTabIndex, setFocusedTabIndex] = useState<number | null>(null);
44-
const tabsRef = useRef<HTMLElement[]>([]);
45-
const tabListRef = useRef<HTMLElement | null>(null);
46-
const tabsValuesRef = useRef<TabValue[]>([]);
34+
const [currentActiveTab, setCurrentActiveTab] = useState<TabValue>(value);
4735

4836
useEffect(() => {
4937
setCurrentActiveTab(value);
5038
}, [value]);
5139

52-
const registerTab = useCallback(
53-
(tabElement: HTMLElement | null, index: number) => {
54-
if (tabElement) {
55-
tabsRef.current[index] = tabElement;
56-
const tabValue = tabElement.getAttribute('data-value');
57-
if (tabValue) {
58-
tabsValuesRef.current[index] = tabValue;
59-
}
60-
}
61-
},
62-
[]
63-
);
64-
65-
const registerTablist = useCallback((tabListElement: HTMLElement | null) => {
66-
tabListRef.current = tabListElement;
67-
}, []);
68-
69-
const onTabClick = useCallback(
70-
(value: TabValue, e: SelectTabEvent) => {
71-
if (!readOnly) {
72-
setCurrentActiveTab(value);
73-
onChange(value, e);
74-
}
75-
},
76-
[onChange, readOnly]
77-
);
78-
79-
const moveFocusToNextTab = useCallback(() => {
80-
const tabValues = tabsValuesRef.current.filter(Boolean);
81-
if (tabValues.length === 0) return;
82-
83-
let currentIndex =
84-
focusedTabIndex !== null
85-
? focusedTabIndex
86-
: tabValues.indexOf(currentActiveTab);
87-
if (currentIndex === -1) currentIndex = 0;
88-
89-
let nextIndex = currentIndex;
90-
do {
91-
nextIndex = (nextIndex + 1) % tabValues.length;
92-
if (nextIndex === currentIndex) break;
93-
} while (disabledTabIndexes.includes(nextIndex));
94-
95-
const nextTab = tabsRef.current[nextIndex];
96-
if (nextTab && !disabledTabIndexes.includes(nextIndex)) {
97-
nextTab.focus();
98-
setFocusedTabIndex(nextIndex);
99-
}
100-
}, [focusedTabIndex, currentActiveTab, disabledTabIndexes]);
101-
102-
const moveFocusToPreviousTab = useCallback(() => {
103-
const tabValues = tabsValuesRef.current.filter(Boolean);
104-
if (tabValues.length == 0) return;
105-
106-
let currentIndex =
107-
focusedTabIndex !== null
108-
? focusedTabIndex
109-
: tabValues.indexOf(currentActiveTab);
110-
if (currentIndex === -1) currentIndex = 0;
111-
112-
let prevIndex = currentIndex;
113-
do {
114-
prevIndex = (prevIndex - 1 + tabValues.length) % tabValues.length;
115-
if (prevIndex === currentIndex) break;
116-
} while (disabledTabIndexes.includes(prevIndex));
117-
118-
const prevTab = tabsRef.current[prevIndex];
119-
if (prevTab && !disabledTabIndexes.includes(prevIndex)) {
120-
prevTab.focus();
121-
setFocusedTabIndex(prevIndex);
122-
}
123-
}, [focusedTabIndex, currentActiveTab, disabledTabIndexes]);
124-
125-
useEffect(() => {
126-
const handleKeyDown = (event: globalThis.KeyboardEvent) => {
127-
if (enableArrowNav) return;
128-
if (event.key == 'Tab') {
129-
const activeElement = document.activeElement;
130-
const tabList = tabListRef.current;
131-
132-
if (
133-
tabList &&
134-
tabList.contains(activeElement) &&
135-
activeElement?.getAttribute('role') === 'tab'
136-
) {
137-
event.preventDefault();
138-
if (event.shiftKey) {
139-
moveFocusToPreviousTab();
140-
} else {
141-
moveFocusToNextTab();
142-
}
143-
}
144-
}
145-
};
146-
document.addEventListener('keydown', handleKeyDown);
147-
return () => {
148-
document.removeEventListener('keydown', handleKeyDown);
149-
};
150-
}, [moveFocusToNextTab, moveFocusToPreviousTab]);
151-
152-
const handleKeyDown = useCallback(
153-
(event: React.KeyboardEvent, tabIndex: number) => {
154-
if (!enableArrowNav || readOnly) return;
155-
156-
if (event.key === 'Tab') {
157-
return;
158-
}
159-
160-
const enableTabIndexes = tabsRef.current
161-
.map((_, index) => index)
162-
.filter((index) => !disabledTabIndexes.includes(index));
163-
164-
const currentEnabledIndex = enableTabIndexes.indexOf(tabIndex);
165-
166-
if (currentEnabledIndex === -1) return;
167-
168-
let nextFocusIndex: number | null = null;
169-
170-
switch (event.key) {
171-
case 'ArrowLeft':
172-
nextFocusIndex =
173-
currentEnabledIndex === 0
174-
? enableTabIndexes[enableTabIndexes.length - 1]
175-
: enableTabIndexes[currentEnabledIndex - 1];
176-
event.preventDefault();
177-
break;
178-
case 'ArrowRight':
179-
nextFocusIndex =
180-
currentEnabledIndex === enableTabIndexes.length - 1
181-
? enableTabIndexes[0]
182-
: enableTabIndexes[currentEnabledIndex + 1];
183-
event.preventDefault();
184-
break;
185-
case 'Home':
186-
nextFocusIndex = enableTabIndexes[0];
187-
event.preventDefault();
188-
break;
189-
case 'End':
190-
nextFocusIndex = enableTabIndexes[enableTabIndexes.length - 1];
191-
event.preventDefault();
192-
break;
193-
case 'Enter':
194-
const currentTab = tabsRef.current[tabIndex];
195-
if (currentTab) {
196-
const tabValue = currentTab.getAttribute('data-value');
197-
if (tabValue) {
198-
setCurrentActiveTab(tabValue);
199-
onChange?.(tabValue, {
200-
currentTarget: currentTab,
201-
} as SelectTabEvent);
202-
}
203-
}
204-
event.preventDefault();
205-
return;
206-
default:
207-
return;
208-
}
209-
210-
if (nextFocusIndex !== null) {
211-
const nextTab = tabsRef.current[nextFocusIndex];
212-
if (nextTab) {
213-
nextTab.focus();
214-
setFocusedTabIndex(nextFocusIndex);
215-
}
216-
}
217-
},
218-
[enableArrowNav, disabledTabIndexes, readOnly, onChange]
219-
);
40+
const onTabClick = (value: TabValue, e: SelectTabEvent) => {
41+
onChange(value, e);
42+
};
22043

22144
return (
22245
<TabsContext.Provider
@@ -236,12 +59,6 @@ const TabsProvider = ({
23659
theme,
23760
themeContainerId,
23861
variant,
239-
registerTab,
240-
registerTablist,
241-
handleKeyDown,
242-
enableArrowNav,
243-
disabledTabIndexes,
244-
focusedTabIndex,
24562
}}
24663
>
24764
{children}

src/components/Tabs/Tabs.stories.tsx

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,13 @@ const tabs = [1, 2, 3, 4].map((i) => ({
7373
value: `tab${i}`,
7474
label: `Tab ${i}`,
7575
ariaLabel: `Tab ${i}`,
76-
id: `tab-${i}`,
7776
...(i === 4 ? { disabled: true } : {}),
7877
}));
7978

8079
const badgeTabs = [1, 2, 3, 4].map((i) => ({
8180
value: `tab${i}`,
8281
label: `Tab ${i}`,
8382
ariaLabel: `Tab ${i}`,
84-
id: `tab-${i}`,
8583
badgeContent: i,
8684
...(i === 4 ? { disabled: true } : {}),
8785
}));
@@ -90,7 +88,6 @@ const iconTabs = [1, 2, 3, 4].map((i) => ({
9088
value: `tab${i}`,
9189
icon: IconName.mdiCardsHeart,
9290
ariaLabel: `Tab ${i}`,
93-
id: `tab-${i}`,
9491
...(i === 4 ? { disabled: true } : {}),
9592
}));
9693

@@ -99,22 +96,16 @@ const iconLabelTabs = [1, 2, 3, 4].map((i) => ({
9996
icon: IconName.mdiCardsHeart,
10097
label: `Tab ${i}`,
10198
ariaLabel: `Tab ${i}`,
102-
id: `tab-${i}`,
10399
...(i === 4 ? { disabled: true } : {}),
104100
}));
105101

106102
const scrollableTabs = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) => ({
107103
value: `tab${i}`,
108104
label: `Tab ${i}`,
109105
ariaLabel: `Tab ${i}`,
110-
id: `tab-${i}`,
111106
...(i === 4 ? { disabled: true } : {}),
112107
}));
113108

114-
const disabledTabIndexes = tabs
115-
.map((tab, index) => (tab.disabled ? index : -1))
116-
.filter((index) => index !== -1);
117-
118109
const Tabs_Story: ComponentStory<typeof Tabs> = (args) => {
119110
const [activeTabs, setActiveTabs] = useState({ defaultTab: 'tab1' });
120111
return (
@@ -132,7 +123,6 @@ const Tabs_Story: ComponentStory<typeof Tabs> = (args) => {
132123
{...args}
133124
onChange={(tab) => setActiveTabs({ ...activeTabs, defaultTab: tab })}
134125
value={activeTabs.defaultTab}
135-
disabledTabIndexes={disabledTabIndexes}
136126
/>
137127
</div>
138128
);
@@ -180,7 +170,6 @@ const tabsArgs: Object = {
180170
variant: TabVariant.default,
181171
size: TabSize.Medium,
182172
underlined: false,
183-
enableArrowNav: false,
184173
children: tabs.map((tab) => <Tab key={tab.value} {...tab} />),
185174
style: {},
186175
};

0 commit comments

Comments
 (0)