fix: record the completed length of the last calculation as the transison length (#43058)

* fix: record the completed width of the last calculation as the transition width in the calculation

* test: add test case

* test: correct test case name

* refactor:rename conut to count

---------

Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
AKing 2023-08-30 23:24:19 +08:00 committed by GitHub
parent 3f148d9112
commit a265257e7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 82 additions and 1 deletions

View File

@ -86,6 +86,8 @@ const Ellipsis: React.FC<EllipsisProps> = ({
const [[startLen, midLen, endLen], setCutLength] = React.useState<
[startLen: number, midLen: number, endLen: number]
>([0, 0, 0]);
// record last done with ellipsis width
const [lastLen, setLastLen] = React.useState(0);
const [walkingState, setWalkingState] = React.useState<WalkingState>(NONE);
const [singleRowHeight, setSingleRowHeight] = React.useState(0);
@ -98,6 +100,10 @@ const Ellipsis: React.FC<EllipsisProps> = ({
const mergedChildren = React.useMemo(() => {
if (!enabledMeasure || walkingState !== DONE_WITH_ELLIPSIS) {
// if has lastLen, use it as temporary width to avoid lots of text to squeeze space.
if (lastLen && walkingState !== DONE_WITHOUT_ELLIPSIS && enabledMeasure)
return children(sliceNodes(nodeList, lastLen), lastLen < totalLen);
return children(nodeList, false);
}
@ -153,6 +159,7 @@ const Ellipsis: React.FC<EllipsisProps> = ({
setCutLength([nextStartLen, nextMidLen, nextEndLen]);
} else {
setWalkingState(DONE_WITH_ELLIPSIS);
setLastLen(midLen);
onEllipsis(true);
}
}

View File

@ -45,7 +45,7 @@ describe('Typography.Ellipsis', () => {
computeSpy = jest
.spyOn(window, 'getComputedStyle')
.mockImplementation(() => ({ fontSize: 12 } as unknown as CSSStyleDeclaration));
.mockImplementation(() => ({ fontSize: 12 }) as unknown as CSSStyleDeclaration);
});
afterEach(() => {
@ -433,4 +433,78 @@ describe('Typography.Ellipsis', () => {
});
mockRectSpy.mockRestore();
});
it('should not throw default dom nodes', async () => {
let currentWidth = 100;
// string count is different with different width
const getLineStrCount = (width: number) => {
const res = width === 100 ? 20 : 17;
return res;
};
const ref = React.createRef<HTMLElement>();
const resize = (width: number) => {
currentWidth = width;
if (ref.current) triggerResize(ref.current);
};
mockRectSpy = spyElementPrototypes(HTMLElement, {
offsetHeight: {
get() {
let html = this.innerHTML;
html = html.replace(/<[^>]*>/g, '');
const lines = Math.ceil(html.length / getLineStrCount(currentWidth));
return lines * 16;
},
},
offsetWidth: {
get: () => currentWidth,
},
getBoundingClientRect() {
let html = this.innerHTML;
html = html.replace(/<[^>]*>/g, '');
const lines = Math.ceil(html.length / getLineStrCount(currentWidth));
return { height: lines * 16 };
},
});
const { container } = render(
<Base
ellipsis={{
rows: 2,
}}
ref={ref}
editable
component="p"
>
{fullStr}
</Base>,
);
// hijackings Math.ceil
const originalCeil = Math.ceil;
let hasDefaultStr = false;
// Math.ceil will be used for ellipsis's calculations;
Math.ceil = (value) => {
const text = container.querySelector('p')?.innerHTML.replace(/<[^>]*>/g, '');
if (text && !text.includes('...')) {
hasDefaultStr = true;
}
return originalCeil.call(Math, value);
};
resize(50);
await waitFakeTimer(20, 1);
// ignore last result
hasDefaultStr = false;
resize(100);
await waitFakeTimer();
expect(hasDefaultStr).not.toBeTruthy();
// reset
mockRectSpy.mockRestore();
Math.ceil = originalCeil;
});
});