Skip to content

Commit c9c9b50

Browse files
committed
feat(Overflow): add prefix prop
1 parent 64ea78f commit c9c9b50

File tree

2 files changed

+56
-27
lines changed

2 files changed

+56
-27
lines changed

examples/fill-width.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ const Demo = () => {
112112
renderItem={renderItem}
113113
renderRest={renderRest}
114114
maxCount={responsive ? 'responsive' : 6}
115+
prefix={<span>Foobar</span>}
115116
suffix={
116117
<div style={{ position: 'relative', maxWidth: '100%' }}>
117118
<input

src/Overflow.tsx

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import * as React from 'react';
2-
import { useState, useMemo, useCallback } from 'react';
31
import classNames from 'classnames';
42
import ResizeObserver from 'rc-resize-observer';
53
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
4+
import * as React from 'react';
5+
import { useCallback, useMemo, useState } from 'react';
66
import Item from './Item';
7-
import useEffectState, { useBatcher } from './hooks/useEffectState';
87
import type { ComponentType } from './RawItem';
98
import RawItem from './RawItem';
109
import { OverflowContext } from './context';
10+
import useEffectState, { useBatcher } from './hooks/useEffectState';
1111

1212
const RESPONSIVE = 'responsive' as const;
1313
const INVALIDATE = 'invalidate' as const;
@@ -16,7 +16,7 @@ export { OverflowContext } from './context';
1616

1717
export type { ComponentType } from './RawItem';
1818

19-
export interface OverflowProps<ItemType> extends React.HTMLAttributes<any> {
19+
export interface OverflowProps<ItemType> extends Omit<React.HTMLAttributes<any>, 'prefix'> {
2020
prefixCls?: string;
2121
className?: string;
2222
style?: React.CSSProperties;
@@ -33,6 +33,7 @@ export interface OverflowProps<ItemType> extends React.HTMLAttributes<any> {
3333
| ((omittedItems: ItemType[]) => React.ReactNode);
3434
/** @private Do not use in your production. Render raw node that need wrap Item by developer self */
3535
renderRawRest?: (omittedItems: ItemType[]) => React.ReactElement;
36+
prefix?: React.ReactNode;
3637
suffix?: React.ReactNode;
3738
component?: ComponentType;
3839
itemComponent?: ComponentType;
@@ -65,6 +66,7 @@ function Overflow<ItemType = any>(
6566
maxCount,
6667
renderRest,
6768
renderRawRest,
69+
prefix,
6870
suffix,
6971
component: Component = 'div',
7072
itemComponent,
@@ -96,6 +98,11 @@ function Overflow<ItemType = any>(
9698
0,
9799
);
98100

101+
const [prefixWidth, setPrefixWidth] = useEffectState<number>(
102+
notifyEffectUpdate,
103+
0,
104+
);
105+
99106
const [suffixWidth, setSuffixWidth] = useEffectState<number>(
100107
notifyEffectUpdate,
101108
0,
@@ -223,6 +230,10 @@ function Overflow<ItemType = any>(
223230
setPrevRestWidth(restWidth);
224231
}
225232

233+
function registerPrefixSize(_: React.Key, width: number | null) {
234+
setPrefixWidth(width!);
235+
}
236+
226237
function registerSuffixSize(_: React.Key, width: number | null) {
227238
setSuffixWidth(width!);
228239
}
@@ -238,7 +249,7 @@ function Overflow<ItemType = any>(
238249
typeof mergedRestWidth === 'number' &&
239250
mergedData
240251
) {
241-
let totalWidth = suffixWidth;
252+
let totalWidth = prefixWidth + suffixWidth;
242253

243254
const len = mergedData.length;
244255
const lastIndex = len - 1;
@@ -286,14 +297,15 @@ function Overflow<ItemType = any>(
286297
}
287298
}
288299

289-
if (suffix && getItemWidth(0) + suffixWidth > mergedContainerWidth) {
300+
if (suffix && getItemWidth(0) + suffixWidth + prefixWidth > mergedContainerWidth) {
290301
setSuffixFixedStart(null);
291302
}
292303
}
293304
}, [
294305
mergedContainerWidth,
295306
itemWidths,
296307
restWidth,
308+
prefixWidth,
297309
suffixWidth,
298310
getKey,
299311
mergedData,
@@ -366,26 +378,26 @@ function Overflow<ItemType = any>(
366378

367379
const mergedRenderRest = renderRest || defaultRenderRest;
368380

369-
const restNode = renderRawRest ? (
370-
<OverflowContext.Provider
371-
value={{
372-
...itemSharedProps,
373-
...restContextProps,
374-
}}
375-
>
376-
{renderRawRest(omittedItems)}
377-
</OverflowContext.Provider>
378-
) : (
379-
<Item
380-
{...itemSharedProps}
381-
// When not show, order should be the last
382-
{...restContextProps}
383-
>
384-
{typeof mergedRenderRest === 'function'
385-
? mergedRenderRest(omittedItems)
386-
: mergedRenderRest}
387-
</Item>
388-
);
381+
const restNode = renderRawRest ? (
382+
<OverflowContext.Provider
383+
value={{
384+
...itemSharedProps,
385+
...restContextProps,
386+
}}
387+
>
388+
{renderRawRest(omittedItems)}
389+
</OverflowContext.Provider>
390+
) : (
391+
<Item
392+
{...itemSharedProps}
393+
// When not show, order should be the last
394+
{...restContextProps}
395+
>
396+
{typeof mergedRenderRest === 'function'
397+
? mergedRenderRest(omittedItems)
398+
: mergedRenderRest}
399+
</Item>
400+
);
389401

390402
const overflowNode = (
391403
<Component
@@ -394,6 +406,20 @@ function Overflow<ItemType = any>(
394406
ref={ref}
395407
{...restProps}
396408
>
409+
{/* Prefix Node */}
410+
{prefix && (
411+
<Item
412+
{...itemSharedProps}
413+
responsive={isResponsive}
414+
responsiveDisabled={!shouldResponsive}
415+
order={mergedDisplayCount}
416+
className={`${itemPrefixCls}-prefix`}
417+
registerSize={registerPrefixSize}
418+
display
419+
>
420+
{prefix}
421+
</Item>
422+
)}
397423
{mergedData.map(internalRenderItemNode)}
398424

399425
{/* Rest Count Item */}
@@ -421,7 +447,9 @@ function Overflow<ItemType = any>(
421447
<ResizeObserver onResize={onOverflowResize} disabled={!shouldResponsive}>
422448
{overflowNode}
423449
</ResizeObserver>
424-
) : overflowNode;
450+
) : (
451+
overflowNode
452+
);
425453
}
426454

427455
const ForwardOverflow = React.forwardRef(Overflow);

0 commit comments

Comments
 (0)