Skip to content

Commit

Permalink
[Tabs] Scroll by width of the first visible tab if only one tab is pa…
Browse files Browse the repository at this point in the history
…rtially visible (#32778)
  • Loading branch information
frankkluijtmans committed Jun 10, 2022
1 parent feb643b commit 66f7a9d
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 0 deletions.
18 changes: 18 additions & 0 deletions packages/mui-material/src/Tabs/Tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,10 +443,27 @@ const Tabs = React.forwardRef(function Tabs(inProps, ref) {
scroll(scrollValue);
};

const getFirstVisibleTab = (tabs) => {
const containerSize = tabsRef.current[clientSize];
const containerStartBound = Math.round(tabsRef.current[scrollStart]);
const containerEndBound = Math.round(containerStartBound + containerSize);

const offset = vertical ? 'offsetTop' : 'offsetLeft';
return tabs.find((tab) => {
const centerPoint = tab[offset] + tab[clientSize] / 2;
return centerPoint >= containerStartBound && centerPoint <= containerEndBound;
});
};

const getScrollSize = () => {
const containerSize = tabsRef.current[clientSize];
let totalSize = 0;
const children = Array.from(tabListRef.current.children);
const firstVisibleTab = getFirstVisibleTab(children);

if (firstVisibleTab && firstVisibleTab[clientSize] > containerSize) {
return firstVisibleTab[clientSize];
}

for (let i = 0; i < children.length; i += 1) {
const tab = children[i];
Expand All @@ -455,6 +472,7 @@ const Tabs = React.forwardRef(function Tabs(inProps, ref) {
}
totalSize += tab[clientSize];
}

return totalSize;
};

Expand Down
50 changes: 50 additions & 0 deletions packages/mui-material/src/Tabs/Tabs.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,56 @@ describe('<Tabs />', () => {
clock.tick(1000);
expect(tablistContainer.scrollLeft).equal(100);
});

it('should horizontally scroll by width of partially visible item', () => {
const { container, getByRole, getAllByRole } = render(
<Tabs value={0} variant="scrollable" scrollButtons style={{ width: 200 }}>
<Tab style={{ width: 220, minWidth: 'auto' }} />
<Tab style={{ width: 200, minWidth: 'auto' }} />
<Tab style={{ width: 200, minWidth: 'auto' }} />
</Tabs>,
);
const tablistContainer = getByRole('tablist').parentElement;
const tabs = getAllByRole('tab');
Object.defineProperty(tablistContainer, 'clientWidth', { value: 200 });
Object.defineProperty(tabs[0], 'clientWidth', { value: 220 });
Object.defineProperty(tabs[1], 'clientWidth', { value: 200 });
Object.defineProperty(tabs[2], 'clientWidth', { value: 200 });
Object.defineProperty(tablistContainer, 'scrollWidth', { value: 620 });

tablistContainer.scrollLeft = 0;
fireEvent.click(findScrollButton(container, 'right'));
clock.tick(1000);
expect(tablistContainer.scrollLeft).equal(220);
});

it('should vertically scroll by width of partially visible item', () => {
const { container, getByRole, getAllByRole } = render(
<Tabs
value={0}
variant="scrollable"
orientation="vertical"
scrollButtons
style={{ height: 100 }}
>
<Tab style={{ height: 48 }} />
<Tab style={{ height: 60 }} />
<Tab style={{ height: 60 }} />
</Tabs>,
);
const tablistContainer = getByRole('tablist').parentElement;
const tabs = getAllByRole('tab');
Object.defineProperty(tablistContainer, 'clientHeight', { value: 100 });
Object.defineProperty(tabs[0], 'clientHeight', { value: 48 });
Object.defineProperty(tabs[1], 'clientHeight', { value: 60 });
Object.defineProperty(tabs[2], 'clientHeight', { value: 60 });
Object.defineProperty(tablistContainer, 'scrollHeight', { value: 168 });

tablistContainer.scrollTop = 0;
fireEvent.click(findScrollButton(container, 'right'));
clock.tick(1000);
expect(tablistContainer.scrollTop).equal(48);
});
});

describe('scroll into view behavior', () => {
Expand Down

0 comments on commit 66f7a9d

Please sign in to comment.