Skip to content

Commit bb0f020

Browse files
authored
Merge cbf13ad into 0553047
2 parents 0553047 + cbf13ad commit bb0f020

File tree

5 files changed

+258
-90
lines changed

5 files changed

+258
-90
lines changed

src/Overflow.tsx

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,6 @@ export interface OverflowProps<ItemType> extends React.HTMLAttributes<any> {
3939

4040
/** @private This API may be refactor since not well design */
4141
onVisibleChange?: (visibleCount: number) => void;
42-
43-
/** When set to `full`, ssr will render full items by default and remove at client side */
44-
ssr?: 'full';
4542
}
4643

4744
function defaultRenderRest<ItemType>(omittedItems: ItemType[]) {
@@ -59,7 +56,6 @@ function Overflow<ItemType = any>(
5956
renderRawItem,
6057
itemKey,
6158
itemWidth = 10,
62-
ssr,
6359
style,
6460
className,
6561
maxCount,
@@ -72,8 +68,6 @@ function Overflow<ItemType = any>(
7268
...restProps
7369
} = props;
7470

75-
const fullySSR = ssr === 'full';
76-
7771
const notifyEffectUpdate = useBatcher();
7872

7973
const [containerWidth, setContainerWidth] = useEffectState<number>(
@@ -104,7 +98,7 @@ function Overflow<ItemType = any>(
10498

10599
const [displayCount, setDisplayCount] = useState<number>(null);
106100
const mergedDisplayCount = React.useMemo(() => {
107-
if (displayCount === null && fullySSR) {
101+
if (displayCount === null) {
108102
return Number.MAX_SAFE_INTEGER;
109103
}
110104

@@ -134,9 +128,7 @@ function Overflow<ItemType = any>(
134128
let items = data;
135129

136130
if (shouldResponsive) {
137-
if (containerWidth === null && fullySSR) {
138-
items = data;
139-
} else {
131+
if (containerWidth !== null) {
140132
items = data.slice(
141133
0,
142134
Math.min(data.length, mergedContainerWidth / itemWidth),
@@ -147,7 +139,14 @@ function Overflow<ItemType = any>(
147139
}
148140

149141
return items;
150-
}, [data, itemWidth, containerWidth, maxCount, shouldResponsive]);
142+
}, [
143+
data,
144+
itemWidth,
145+
containerWidth,
146+
maxCount,
147+
shouldResponsive,
148+
mergedContainerWidth,
149+
]);
151150

152151
const omittedItems = useMemo(() => {
153152
if (shouldResponsive) {
@@ -250,12 +249,7 @@ function Overflow<ItemType = any>(
250249
}
251250

252251
for (let i = 0; i < len; i += 1) {
253-
let currentItemWidth = getItemWidth(i);
254-
255-
// Fully will always render
256-
if (fullySSR) {
257-
currentItemWidth = currentItemWidth || 0;
258-
}
252+
const currentItemWidth = getItemWidth(i);
259253

260254
// Break since data not ready
261255
if (currentItemWidth === undefined) {
@@ -301,8 +295,18 @@ function Overflow<ItemType = any>(
301295

302296
// ================================ Render ================================
303297
const displayRest = restReady && !!omittedItems.length;
298+
const isResponsiveAndFirstRender = isResponsive && containerWidth === null;
299+
const responsiveAndFirstRenderStyle: React.CSSProperties = {
300+
maxWidth: 0,
301+
padding: 0,
302+
margin: 0,
303+
borderWidth: 0,
304+
overflowX: 'hidden',
305+
};
304306

305-
let suffixStyle: React.CSSProperties = {};
307+
let suffixStyle: React.CSSProperties = isResponsiveAndFirstRender
308+
? responsiveAndFirstRenderStyle
309+
: {};
306310
if (suffixFixedStart !== null && shouldResponsive) {
307311
suffixStyle = {
308312
position: 'absolute',
@@ -316,12 +320,22 @@ function Overflow<ItemType = any>(
316320
responsive: shouldResponsive,
317321
component: itemComponent,
318322
invalidate,
323+
style: isResponsiveAndFirstRender
324+
? responsiveAndFirstRenderStyle
325+
: undefined,
319326
};
320327

321328
// >>>>> Choice render fun by `renderRawItem`
322329
const internalRenderItemNode = renderRawItem
323330
? (item: ItemType, index: number) => {
324331
const key = getKey(item, index);
332+
const isIdxCheckPass = index <= mergedDisplayCount;
333+
// in responsive case, item's `display` can be set to `true` when:
334+
// 1) at initial render; 2) its corresponding width is valid and pass the index check
335+
const shouldDisplay = isResponsive
336+
? isResponsiveAndFirstRender ||
337+
(isIdxCheckPass && getItemWidth(index) > 0)
338+
: isIdxCheckPass;
325339

326340
return (
327341
<OverflowContext.Provider
@@ -332,7 +346,7 @@ function Overflow<ItemType = any>(
332346
item,
333347
itemKey: key,
334348
registerSize,
335-
display: index <= mergedDisplayCount,
349+
display: shouldDisplay,
336350
}}
337351
>
338352
{renderRawItem(item, index)}
@@ -341,6 +355,12 @@ function Overflow<ItemType = any>(
341355
}
342356
: (item: ItemType, index: number) => {
343357
const key = getKey(item, index);
358+
const isIdxCheckPass = index <= mergedDisplayCount;
359+
360+
const shouldDisplay = isResponsive
361+
? isResponsiveAndFirstRender ||
362+
(isIdxCheckPass && getItemWidth(index) > 0)
363+
: isIdxCheckPass;
344364

345365
return (
346366
<Item
@@ -351,7 +371,7 @@ function Overflow<ItemType = any>(
351371
renderItem={mergedRenderItem}
352372
itemKey={key}
353373
registerSize={registerSize}
354-
display={index <= mergedDisplayCount}
374+
display={shouldDisplay}
355375
/>
356376
);
357377
};

tests/__snapshots__/seo.spec.tsx.snap

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`Overflow.SEO invalidate number with suffix 1`] = `
4+
<div
5+
class=""
6+
>
7+
<div
8+
class=""
9+
>
10+
Label 0
11+
</div>
12+
<div
13+
class=""
14+
>
15+
Label 1
16+
</div>
17+
<div
18+
class=""
19+
>
20+
Label 2
21+
</div>
22+
<div
23+
class=""
24+
>
25+
Label 3
26+
</div>
27+
<div
28+
class="rc-overflow-item-suffix"
29+
>
30+
<span>
31+
I am a suffix
32+
</span>
33+
</div>
34+
</div>
35+
`;
36+
37+
exports[`Overflow.SEO maxCount number with suffix 1`] = `
38+
<div
39+
class="rc-overflow"
40+
>
41+
<div
42+
class="rc-overflow-item"
43+
style="opacity:1"
44+
>
45+
Label 0
46+
</div>
47+
<div
48+
class="rc-overflow-item"
49+
style="opacity:1"
50+
>
51+
Label 1
52+
</div>
53+
<div
54+
class="rc-overflow-item"
55+
style="opacity:1"
56+
>
57+
Label 2
58+
</div>
59+
<div
60+
class="rc-overflow-item"
61+
style="opacity:1"
62+
>
63+
Label 3
64+
</div>
65+
<div
66+
class="rc-overflow-item rc-overflow-item-rest"
67+
style="opacity:1"
68+
>
69+
+ 2 ...
70+
</div>
71+
<div
72+
class="rc-overflow-item rc-overflow-item-suffix"
73+
style="opacity:1"
74+
>
75+
<span>
76+
I am a suffix
77+
</span>
78+
</div>
79+
</div>
80+
`;
81+
82+
exports[`Overflow.SEO responsive 1`] = `
83+
<div
84+
class="rc-overflow"
85+
>
86+
<div
87+
class="rc-overflow-item"
88+
style="opacity:1;order:0;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
89+
>
90+
Label 0
91+
</div>
92+
<div
93+
class="rc-overflow-item"
94+
style="opacity:1;order:1;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
95+
>
96+
Label 1
97+
</div>
98+
<div
99+
aria-hidden="true"
100+
class="rc-overflow-item rc-overflow-item-rest"
101+
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
102+
>
103+
+ 0 ...
104+
</div>
105+
</div>
106+
`;
107+
108+
exports[`Overflow.SEO responsive with suffix 1`] = `
109+
<div
110+
class="rc-overflow"
111+
>
112+
<div
113+
class="rc-overflow-item"
114+
style="opacity:1;order:0;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
115+
>
116+
Label 0
117+
</div>
118+
<div
119+
class="rc-overflow-item"
120+
style="opacity:1;order:1;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
121+
>
122+
Label 1
123+
</div>
124+
<div
125+
aria-hidden="true"
126+
class="rc-overflow-item rc-overflow-item-rest"
127+
style="opacity:0;height:0;overflow-y:hidden;order:9007199254740991;pointer-events:none;position:absolute;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
128+
>
129+
+ 0 ...
130+
</div>
131+
<div
132+
class="rc-overflow-item rc-overflow-item-suffix"
133+
style="opacity:1;order:9007199254740991;max-width:0;padding:0;margin:0;border-width:0;overflow-x:hidden"
134+
>
135+
<span>
136+
I am a suffix
137+
</span>
138+
</div>
139+
</div>
140+
`;

tests/__snapshots__/ssr.spec.tsx.snap

Lines changed: 0 additions & 27 deletions
This file was deleted.

tests/seo.spec.tsx

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React from 'react';
2+
import { render } from 'enzyme';
3+
import Overflow from '../src';
4+
import type { OverflowProps } from '../src';
5+
6+
interface ItemType {
7+
label: React.ReactNode;
8+
key: React.Key;
9+
}
10+
11+
interface CaseConf {
12+
name: string;
13+
dataLength: number;
14+
maxCount: OverflowProps<ItemType>['maxCount'];
15+
suffix?: boolean;
16+
}
17+
18+
function renderItem(item: ItemType) {
19+
return item.label;
20+
}
21+
22+
describe('Overflow.SEO', () => {
23+
function getData(count: number) {
24+
return new Array(count).fill(undefined).map((_, index) => ({
25+
label: `Label ${index}`,
26+
key: `k-${index}`,
27+
}));
28+
}
29+
30+
beforeEach(() => {
31+
jest.useFakeTimers();
32+
});
33+
34+
afterEach(() => {
35+
jest.useRealTimers();
36+
});
37+
38+
const testCases: CaseConf[] = [
39+
{
40+
name: 'responsive',
41+
dataLength: 2,
42+
maxCount: 'responsive',
43+
},
44+
{
45+
name: 'responsive with suffix',
46+
dataLength: 2,
47+
maxCount: 'responsive',
48+
suffix: true,
49+
},
50+
{
51+
name: 'maxCount number with suffix',
52+
dataLength: 6,
53+
maxCount: 4,
54+
suffix: true,
55+
},
56+
{
57+
name: 'invalidate number with suffix',
58+
dataLength: 4,
59+
maxCount: 'invalidate',
60+
suffix: true,
61+
},
62+
];
63+
64+
testCases.forEach(({ name, dataLength, maxCount: maxCountVal, suffix }) => {
65+
it(`${name}`, () => {
66+
const wrapper = render(
67+
<Overflow<ItemType>
68+
data={getData(dataLength)}
69+
renderItem={renderItem}
70+
maxCount={maxCountVal}
71+
suffix={suffix && <span> I am a suffix </span>}
72+
/>,
73+
);
74+
75+
expect(wrapper).toMatchSnapshot();
76+
});
77+
});
78+
});

0 commit comments

Comments
 (0)