Skip to content

Commit

Permalink
Merge fc31b64 into ad50b0a
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ authored Oct 16, 2023
2 parents ad50b0a + fc31b64 commit 222711c
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 37 deletions.
95 changes: 62 additions & 33 deletions src/TabNavList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import useEvent from 'rc-util/lib/hooks/useEvent';
import { useComposeRef } from 'rc-util/lib/ref';
import * as React from 'react';
import { useEffect, useRef, useState } from 'react';
import type { GetIndicatorSize } from '../hooks/useIndicator';
import useIndicator from '../hooks/useIndicator';
import useOffsets from '../hooks/useOffsets';
import useSyncState from '../hooks/useSyncState';
import useTouchMove from '../hooks/useTouchMove';
Expand All @@ -26,8 +28,6 @@ import AddButton from './AddButton';
import ExtraContent from './ExtraContent';
import OperationNode from './OperationNode';
import TabNode from './TabNode';
import useIndicator from '../hooks/useIndicator';
import type { GetIndicatorSize } from '../hooks/useIndicator';

export interface TabNavListProps {
id: string;
Expand All @@ -53,8 +53,31 @@ export interface TabNavListProps {
indicatorSize?: GetIndicatorSize;
}

const getTabSize = (tab: HTMLElement, containerRect: { x: number; y: number }) => {
// tabListRef
const { offsetWidth, offsetHeight, offsetTop, offsetLeft } = tab;
const { width, height, x, y } = tab.getBoundingClientRect();

// Use getBoundingClientRect to avoid decimal inaccuracy
if (Math.abs(width - offsetWidth) < 1) {
return [width, height, x - containerRect.x, y - containerRect.y];
}

return [offsetWidth, offsetHeight, offsetLeft, offsetTop];
};

const getSize = (refObj: React.RefObject<HTMLElement>): SizeInfo => {
const { offsetWidth = 0, offsetHeight = 0 } = refObj.current || {};

// Use getBoundingClientRect to avoid decimal inaccuracy
if (refObj.current) {
const { width, height } = refObj.current.getBoundingClientRect();

if (Math.abs(width - offsetWidth) < 1) {
return [width, height];

Check warning on line 77 in src/TabNavList/index.tsx

View check run for this annotation

Codecov / codecov/patch

src/TabNavList/index.tsx#L77

Added line #L77 was not covered by tests
}
}

return [offsetWidth, offsetHeight];
};

Expand Down Expand Up @@ -313,14 +336,20 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
const updateTabSizes = () =>
setTabSizes(() => {
const newSizes: TabSizeMap = new Map();
const listRect = tabListRef.current?.getBoundingClientRect();

tabs.forEach(({ key }) => {
const btnNode = tabListRef.current?.querySelector<HTMLElement>(`[data-node-key="${genDataNodeKey(key)}"]`);
const btnNode = tabListRef.current?.querySelector<HTMLElement>(
`[data-node-key="${genDataNodeKey(key)}"]`,
);
if (btnNode) {
const [width, height, left, top] = getTabSize(btnNode, listRect);

newSizes.set(key, {
width: btnNode.offsetWidth,
height: btnNode.offsetHeight,
left: btnNode.offsetLeft,
top: btnNode.offsetTop,
width,
height,
left,
top,
});
}
});
Expand Down Expand Up @@ -370,7 +399,7 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
horizontal: tabPositionTopOrBottom,
rtl,
indicatorSize,
})
});

// ========================= Effect ========================
useEffect(() => {
Expand Down Expand Up @@ -437,33 +466,33 @@ function TabNavList(props: TabNavListProps, ref: React.Ref<HTMLDivElement>) {
ref={tabsWrapperRef}
>
<ResizeObserver onResize={onListHolderResize}>
<div
ref={tabListRef}
className={`${prefixCls}-nav-list`}
style={{
transform: `translate(${transformLeft}px, ${transformTop}px)`,
transition: lockAnimation ? 'none' : undefined,
}}
>
{tabNodes}
<AddButton
ref={innerAddButtonRef}
prefixCls={prefixCls}
locale={locale}
editable={editable}
<div
ref={tabListRef}
className={`${prefixCls}-nav-list`}
style={{
...(tabNodes.length === 0 ? undefined : tabNodeStyle),
visibility: hasDropdown ? 'hidden' : null,
transform: `translate(${transformLeft}px, ${transformTop}px)`,
transition: lockAnimation ? 'none' : undefined,
}}
/>

<div
className={classNames(`${prefixCls}-ink-bar`, {
[`${prefixCls}-ink-bar-animated`]: animated.inkBar,
})}
style={indicatorStyle}
/>
</div>
>
{tabNodes}
<AddButton
ref={innerAddButtonRef}
prefixCls={prefixCls}
locale={locale}
editable={editable}
style={{
...(tabNodes.length === 0 ? undefined : tabNodeStyle),
visibility: hasDropdown ? 'hidden' : null,
}}
/>

<div
className={classNames(`${prefixCls}-ink-bar`, {
[`${prefixCls}-ink-bar-animated`]: animated.inkBar,
})}
style={indicatorStyle}
/>
</div>
</ResizeObserver>
</div>
</ResizeObserver>
Expand Down
14 changes: 11 additions & 3 deletions tests/common/util.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-invalid-this */
import { act } from '@testing-library/react';
import type { ReactWrapper } from 'enzyme';
import { _rs as onEsResize } from 'rc-resize-observer/es/utils/observerUtil';
import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil';
import React from 'react';
Expand All @@ -17,6 +16,7 @@ import type { TabsProps } from '../../src/Tabs';
export interface HackInfo {
container?: number;
tabNode?: number;
tabNodeList?: number;
add?: number;
more?: number;
extra?: number;
Expand All @@ -25,7 +25,15 @@ export interface HackInfo {

export function getOffsetSizeFunc(info: HackInfo = {}) {
return function getOffsetSize() {
const { container = 50, extra = 10, tabNode = 20, add = 10, more = 10, dropdown = 10 } = info;
const {
container = 50,
extra = 10,
tabNodeList,
tabNode = 20,
add = 10,
more = 10,
dropdown = 10,
} = info;

if (this.classList.contains('rc-tabs-nav')) {
return container;
Expand All @@ -36,7 +44,7 @@ export function getOffsetSizeFunc(info: HackInfo = {}) {
}

if (this.classList.contains('rc-tabs-nav-list')) {
return this.querySelectorAll('.rc-tabs-tab').length * tabNode + add;
return tabNodeList || this.querySelectorAll('.rc-tabs-tab').length * tabNode + add;
}

if (this.classList.contains('rc-tabs-tab')) {
Expand Down
75 changes: 74 additions & 1 deletion tests/overflow.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ import {
getTabs,
getTransformX,
getTransformY,
triggerResize, waitFakeTimer,
triggerResize,
} from './common/util';

describe('Tabs.Overflow', () => {
let domSpy: ReturnType<typeof spyElementPrototypes>;

const hackOffsetInfo: HackInfo = {};

let mockGetBoundingClientRect: (
ele: HTMLElement,
) => { x: number; y: number; width: number; height: number } | void = null;

beforeEach(() => {
mockGetBoundingClientRect = null;

Object.keys(hackOffsetInfo).forEach(key => {
delete hackOffsetInfo[key];
});
Expand All @@ -40,6 +46,16 @@ describe('Tabs.Overflow', () => {
offsetTop: {
get: btnOffsetPosition,
},
getBoundingClientRect() {
return (
mockGetBoundingClientRect?.(this) || {
x: 0,
y: 0,
width: 0,
height: 0,
}
);
},
});
});

Expand Down Expand Up @@ -483,4 +499,61 @@ describe('Tabs.Overflow', () => {
});
expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('custom-popup');
});

it('correct handle decimal', () => {
hackOffsetInfo.container = 29;
hackOffsetInfo.tabNodeList = 29;
hackOffsetInfo.tabNode = 15;

mockGetBoundingClientRect = ele => {
if (ele.classList.contains('rc-tabs-tab')) {
const sharedRect = {
x: 0,
y: 0,
width: 14.5,
height: 14.5,
};

return ele.getAttribute('data-node-key') === 'bamboo'
? {
...sharedRect,
}
: {
...sharedRect,
x: 14.5,
};
}
// console.log('ele!!!', ele.className);
};

jest.useFakeTimers();
const { container } = render(
getTabs({
defaultActiveKey: 'little',
items: [
{
label: 'bamboo',
key: 'bamboo',
children: 'Bamboo',
},
{
label: 'little',
key: 'little',
children: 'Little',
},
],
}),
);

act(() => {
jest.runAllTimers();
});

expect(container.querySelector('.rc-tabs-nav-operations-hidden')).toBeTruthy();
expect(container.querySelector('.rc-tabs-ink-bar')).toHaveStyle({
left: '21.75px',
});

jest.useRealTimers();
});
});

0 comments on commit 222711c

Please sign in to comment.