|
5 | 5 | * LICENSE file in the root directory of this source tree.
|
6 | 6 | * ========================================================================== */
|
7 | 7 |
|
8 |
| -import React, { cloneElement, ReactElement } from "react"; |
| 8 | +import React, { cloneElement, ReactElement, useEffect, useRef } from "react"; |
9 | 9 |
|
10 | 10 | import {
|
11 | 11 | sanitizeTabsChildren,
|
@@ -43,18 +43,31 @@ function TabList({
|
43 | 43 | selectValue,
|
44 | 44 | tabValues,
|
45 | 45 | }: CodeTabsProps & ReturnType<typeof useTabs>) {
|
46 |
| - const tabRefs: (HTMLLIElement | null)[] = []; |
| 46 | + const tabRefs = useRef<(HTMLLIElement | null)[]>([]); |
47 | 47 | const { blockElementScrollPositionUntilNextRender } =
|
48 | 48 | useScrollPositionBlocker();
|
49 | 49 |
|
| 50 | + useEffect(() => { |
| 51 | + const activeTab = tabRefs.current.find( |
| 52 | + (tab) => tab?.getAttribute("aria-selected") === "true" |
| 53 | + ); |
| 54 | + if (activeTab) { |
| 55 | + activeTab.scrollIntoView({ |
| 56 | + behavior: "auto", |
| 57 | + block: "center", |
| 58 | + inline: "start", |
| 59 | + }); |
| 60 | + } |
| 61 | + }, []); |
| 62 | + |
50 | 63 | const handleTabChange = (
|
51 | 64 | event:
|
52 | 65 | | React.FocusEvent<HTMLLIElement>
|
53 | 66 | | React.MouseEvent<HTMLLIElement>
|
54 | 67 | | React.KeyboardEvent<HTMLLIElement>
|
55 | 68 | ) => {
|
56 | 69 | const newTab = event.currentTarget;
|
57 |
| - const newTabIndex = tabRefs.indexOf(newTab); |
| 70 | + const newTabIndex = tabRefs.current.indexOf(newTab); |
58 | 71 | const newTabValue = tabValues[newTabIndex]!.value;
|
59 | 72 |
|
60 | 73 | if (newTabValue !== selectedValue) {
|
@@ -96,13 +109,15 @@ function TabList({
|
96 | 109 | break;
|
97 | 110 | }
|
98 | 111 | case "ArrowRight": {
|
99 |
| - const nextTab = tabRefs.indexOf(event.currentTarget) + 1; |
100 |
| - focusElement = tabRefs[nextTab] ?? tabRefs[0]!; |
| 112 | + const nextTab = tabRefs.current.indexOf(event.currentTarget) + 1; |
| 113 | + focusElement = tabRefs.current[nextTab] ?? tabRefs.current[0]!; |
101 | 114 | break;
|
102 | 115 | }
|
103 | 116 | case "ArrowLeft": {
|
104 |
| - const prevTab = tabRefs.indexOf(event.currentTarget) - 1; |
105 |
| - focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!; |
| 117 | + const prevTab = tabRefs.current.indexOf(event.currentTarget) - 1; |
| 118 | + focusElement = |
| 119 | + tabRefs.current[prevTab] ?? |
| 120 | + tabRefs.current[tabRefs.current.length - 1]!; |
106 | 121 | break;
|
107 | 122 | }
|
108 | 123 | default:
|
@@ -132,7 +147,7 @@ function TabList({
|
132 | 147 | tabIndex={selectedValue === value ? 0 : -1}
|
133 | 148 | aria-selected={selectedValue === value}
|
134 | 149 | key={value}
|
135 |
| - ref={(tabControl) => tabRefs.push(tabControl)} |
| 150 | + ref={(tabControl) => tabRefs.current.push(tabControl)} |
136 | 151 | onKeyDown={handleKeydown}
|
137 | 152 | onClick={handleTabChange}
|
138 | 153 | {...attributes}
|
|
0 commit comments