Skip to content

Commit ae63ced

Browse files
authored
feat: Support placement (#661)
1 parent d360fdd commit ae63ced

File tree

5 files changed

+33
-7
lines changed

5 files changed

+33
-7
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@
5353
"rc-virtual-list": "^3.2.0"
5454
},
5555
"devDependencies": {
56-
"@types/enzyme": "^3.10.5",
57-
"@types/jest": "^26.0.0",
56+
"@types/enzyme": "^3.10.9",
57+
"@types/jest": "^26.0.24",
5858
"@types/react": "^17.0.15",
5959
"@types/react-dom": "^17.0.3",
6060
"cross-env": "^7.0.0",

src/SelectTrigger.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import Trigger from 'rc-trigger';
33
import classNames from 'classnames';
44
import type { RenderDOMFunc } from './interface';
5+
import type { Placement } from './generate';
56

67
const getBuiltInPlacements = (dropdownMatchSelectWidth: number | boolean) => {
78
// Enable horizontal overflow auto-adjustment when a custom dropdown width is provided
@@ -57,6 +58,7 @@ export interface SelectTriggerProps {
5758
animation?: string;
5859
transitionName?: string;
5960
containerWidth: number;
61+
placement?: Placement;
6062
dropdownStyle: React.CSSProperties;
6163
dropdownClassName: string;
6264
direction: string;
@@ -86,6 +88,7 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
8688
dropdownStyle,
8789
dropdownClassName,
8890
direction = 'ltr',
91+
placement,
8992
dropdownMatchSelectWidth = true,
9093
dropdownRender,
9194
dropdownAlign,
@@ -103,9 +106,10 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
103106
popupNode = dropdownRender(popupElement);
104107
}
105108

106-
const builtInPlacements = React.useMemo(() => getBuiltInPlacements(dropdownMatchSelectWidth), [
107-
dropdownMatchSelectWidth,
108-
]);
109+
const builtInPlacements = React.useMemo(
110+
() => getBuiltInPlacements(dropdownMatchSelectWidth),
111+
[dropdownMatchSelectWidth],
112+
);
109113

110114
// ===================== Motion ======================
111115
const mergedTransitionName = animation ? `${dropdownPrefixCls}-${animation}` : transitionName;
@@ -133,7 +137,7 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
133137
{...restProps}
134138
showAction={onPopupVisibleChange ? ['click'] : []}
135139
hideAction={onPopupVisibleChange ? ['click'] : []}
136-
popupPlacement={direction === 'rtl' ? 'bottomRight' : 'bottomLeft'}
140+
popupPlacement={placement || (direction === 'rtl' ? 'bottomRight' : 'bottomLeft')}
137141
builtinPlacements={builtInPlacements}
138142
prefixCls={dropdownPrefixCls}
139143
popupTransitionName={mergedTransitionName}

src/generate.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ export interface RefSelectProps {
6666
scrollTo?: ScrollTo;
6767
}
6868

69+
export type Placement = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight';
70+
6971
export interface SelectProps<OptionsType extends object[], ValueType> extends React.AriaAttributes {
7072
prefixCls?: string;
7173
id?: string;
@@ -119,6 +121,7 @@ export interface SelectProps<OptionsType extends object[], ValueType> extends Re
119121
dropdownStyle?: React.CSSProperties;
120122
dropdownClassName?: string;
121123
dropdownMatchSelectWidth?: boolean | number;
124+
placement?: Placement;
122125
virtual?: boolean;
123126
dropdownRender?: (menu: React.ReactElement) => React.ReactElement;
124127
dropdownAlign?: any;
@@ -301,6 +304,7 @@ export default function generateSelector<
301304
getPopupContainer,
302305

303306
// Dropdown
307+
placement,
304308
listHeight = 200,
305309
listItemHeight = 20,
306310
animation,
@@ -1075,6 +1079,7 @@ export default function generateSelector<
10751079
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
10761080
dropdownRender={dropdownRender}
10771081
dropdownAlign={dropdownAlign}
1082+
placement={placement}
10781083
getPopupContainer={getPopupContainer}
10791084
empty={!mergedOptions.length}
10801085
getTriggerDOMNode={() => selectorDomRef.current}

tests/Select.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1680,4 +1680,21 @@ describe('Select.Basic', () => {
16801680
wrapper.find('input.rc-select-selection-search-input').getDOMNode().getAttribute('tabindex'),
16811681
).toBe('0');
16821682
});
1683+
1684+
describe('placement', () => {
1685+
it('default', () => {
1686+
const wrapper = mount(<Select open />);
1687+
expect(wrapper.find('Trigger').prop('popupPlacement')).toEqual('bottomLeft');
1688+
});
1689+
1690+
it('rtl', () => {
1691+
const wrapper = mount(<Select direction="rtl" open />);
1692+
expect(wrapper.find('Trigger').prop('popupPlacement')).toEqual('bottomRight');
1693+
});
1694+
1695+
it('customize', () => {
1696+
const wrapper = mount(<Select placement="topRight" open />);
1697+
expect(wrapper.find('Trigger').prop('popupPlacement')).toEqual('topRight');
1698+
});
1699+
});
16831700
});

tests/SelectTrigger.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ describe('Select.Trigger', () => {
1212
</SimpleSelectTrigger>,
1313
);
1414

15-
expect(wrapper.find('Trigger').props().popupTransitionName).toBe('rc-select-dropdown-slide-up');
15+
expect(wrapper.find('Trigger').prop('popupTransitionName')).toBe('rc-select-dropdown-slide-up');
1616
});
1717
});

0 commit comments

Comments
 (0)