Skip to content

Commit 0990797

Browse files
author
刘欢
committed
feat:使用list中漏出的showScrollBar属性
1 parent 07e1c57 commit 0990797

File tree

4 files changed

+151
-2
lines changed

4 files changed

+151
-2
lines changed

src/BaseSelect/index.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export interface BaseSelectProps extends BaseSelectPrivateProps, React.AriaAttri
136136
tagRender?: (props: CustomTagProps) => React.ReactElement;
137137
direction?: 'ltr' | 'rtl';
138138
maxLength?: number;
139-
139+
showScrollBar?: boolean | 'optional';
140140
// MISC
141141
tabIndex?: number;
142142
autoFocus?: boolean;
@@ -223,7 +223,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
223223
tagRender,
224224
direction,
225225
omitDomProps,
226-
226+
showScrollBar = 'optional',
227227
// Value
228228
displayValues,
229229
onDisplayValuesChange,
@@ -686,6 +686,7 @@ const BaseSelect = React.forwardRef<BaseSelectRef, BaseSelectProps>((props, ref)
686686
showSearch: mergedShowSearch,
687687
multiple,
688688
toggleOpen: onToggleOpen,
689+
showScrollBar,
689690
}),
690691
[props, notFoundContent, triggerOpen, mergedOpen, id, mergedShowSearch, multiple, onToggleOpen],
691692
);

src/OptionList.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const OptionList: React.ForwardRefRenderFunction<RefOptionListProps, {}> = (_, r
4444
toggleOpen,
4545
notFoundContent,
4646
onPopupScroll,
47+
showScrollBar,
4748
} = useBaseProps();
4849
const {
4950
maxCount,
@@ -325,6 +326,7 @@ const OptionList: React.ForwardRefRenderFunction<RefOptionListProps, {}> = (_, r
325326
virtual={virtual}
326327
direction={direction}
327328
innerProps={virtual ? null : a11yProps}
329+
showScrollBar={showScrollBar}
328330
>
329331
{(item, itemIndex) => {
330332
const { group, groupOption, data, label, value } = item;

tests/ListScrollBar.test.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import React from 'react';
2+
import { render, waitFor } from '@testing-library/react';
3+
import { spyElementPrototypes } from './utils/domHook';
4+
import Select from '../src';
5+
6+
jest.mock('../src/utils/platformUtil');
7+
// Mock VirtualList
8+
jest.mock('rc-virtual-list', () => {
9+
const OriReact = jest.requireActual('react');
10+
const OriList = jest.requireActual('rc-virtual-list').default;
11+
12+
return OriReact.forwardRef((props, ref) => {
13+
const oriRef = OriReact.useRef();
14+
15+
OriReact.useImperativeHandle(ref, () => ({
16+
...oriRef.current,
17+
scrollTo: (arg) => {
18+
global.scrollToArgs = arg;
19+
oriRef.current.scrollTo(arg);
20+
},
21+
}));
22+
23+
return <OriList {...props} ref={oriRef} />;
24+
});
25+
});
26+
27+
describe('List.Scroll', () => {
28+
let mockElement;
29+
let boundingRect = {
30+
top: 0,
31+
bottom: 0,
32+
width: 100,
33+
height: 50,
34+
};
35+
36+
beforeAll(() => {
37+
// Mock the required properties
38+
mockElement = spyElementPrototypes(HTMLElement, {
39+
offsetHeight: {
40+
get: () => 100, // Ensure this indicates there is enough height for content
41+
},
42+
clientHeight: {
43+
get: () => 50, // This is typically the visible height
44+
},
45+
getBoundingClientRect: () => boundingRect, // Setup for the bounding rectangle
46+
offsetParent: {
47+
get: () => document.body,
48+
},
49+
});
50+
});
51+
52+
afterAll(() => {
53+
mockElement.mockRestore();
54+
});
55+
56+
beforeEach(() => {
57+
boundingRect = {
58+
top: 0,
59+
bottom: 0,
60+
width: 100,
61+
height: 50,
62+
};
63+
jest.useFakeTimers();
64+
});
65+
66+
afterEach(() => {
67+
jest.useRealTimers();
68+
});
69+
70+
it('should show scrollbar when showScrollBar is true', async () => {
71+
const options = Array.from({ length: 10 }, (_, index) => ({
72+
label: `${index + 1}`,
73+
value: `${index + 1}`,
74+
}));
75+
76+
// Render the Select component with a scrollbar
77+
const { container } = render(<Select open showScrollBar options={options} />);
78+
79+
// Wait for the scrollbar to appear
80+
await waitFor(() => {
81+
const scrollbarElement = container.querySelector('.rc-virtual-list-scrollbar-visible');
82+
expect(scrollbarElement).not.toBeNull();
83+
});
84+
});
85+
});

tests/utils/domHook.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* eslint-disable no-param-reassign */
2+
const NO_EXIST = { __NOT_EXIST: true };
3+
4+
export function spyElementPrototypes(Element, properties) {
5+
const propNames = Object.keys(properties);
6+
const originDescriptors = {};
7+
8+
propNames.forEach((propName) => {
9+
const originDescriptor = Object.getOwnPropertyDescriptor(Element.prototype, propName);
10+
originDescriptors[propName] = originDescriptor || NO_EXIST;
11+
12+
const spyProp = properties[propName];
13+
14+
if (typeof spyProp === 'function') {
15+
// If is a function
16+
Element.prototype[propName] = function spyFunc(...args) {
17+
return spyProp.call(this, originDescriptor, ...args);
18+
};
19+
} else {
20+
// Otherwise tread as a property
21+
Object.defineProperty(Element.prototype, propName, {
22+
...spyProp,
23+
set(value) {
24+
if (spyProp.set) {
25+
return spyProp.set.call(this, originDescriptor, value);
26+
}
27+
return originDescriptor.set(value);
28+
},
29+
get() {
30+
if (spyProp.get) {
31+
return spyProp.get.call(this, originDescriptor);
32+
}
33+
return originDescriptor.get();
34+
},
35+
configurable: true,
36+
});
37+
}
38+
});
39+
40+
return {
41+
mockRestore() {
42+
propNames.forEach((propName) => {
43+
const originDescriptor = originDescriptors[propName];
44+
if (originDescriptor === NO_EXIST) {
45+
delete Element.prototype[propName];
46+
} else if (typeof originDescriptor === 'function') {
47+
Element.prototype[propName] = originDescriptor;
48+
} else {
49+
Object.defineProperty(Element.prototype, propName, originDescriptor);
50+
}
51+
});
52+
},
53+
};
54+
}
55+
56+
export function spyElementPrototype(Element, propName, property) {
57+
return spyElementPrototypes(Element, {
58+
[propName]: property,
59+
});
60+
}
61+
/* eslint-enable no-param-reassign */

0 commit comments

Comments
 (0)