Skip to content

Commit a64b6ba

Browse files
authored
refactor: Select use @rc-component/trigger align logic instead of self measure (#976)
* chore: use trigger stretch * test: update snapshot
1 parent 2decf05 commit a64b6ba

File tree

5 files changed

+86
-60
lines changed

5 files changed

+86
-60
lines changed

docs/examples/getPopupContainer.tsx

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,30 @@
1-
import '../../assets/index.less';
21
import 'rc-dialog/assets/index.css';
2+
import '../../assets/index.less';
33

44
import Dialog from 'rc-dialog';
5+
import Select, { type SelectProps } from 'rc-select';
56
import React from 'react';
6-
import Select, { Option } from 'rc-select';
7+
8+
const MySelect = (props: Partial<SelectProps>) => (
9+
<Select
10+
placeholder="placeholder"
11+
style={{ width: 100 }}
12+
getPopupContainer={(node) => node.parentNode}
13+
options={new Array(3).fill(null).map((_, index) => ({
14+
value: index,
15+
label: `long_label_${index}`,
16+
}))}
17+
{...props}
18+
/>
19+
);
720

821
class Test extends React.Component {
922
state = {
1023
open: false,
1124
destroy: false,
1225
};
1326

14-
getPopupContainer = node => node.parentNode;
15-
16-
setVisible = open => {
27+
setVisible = (open) => {
1728
this.setState({
1829
open,
1930
});
@@ -38,6 +49,7 @@ class Test extends React.Component {
3849
if (destroy) {
3950
return null;
4051
}
52+
4153
return (
4254
<div>
4355
<button type="button" onClick={this.open}>
@@ -49,17 +61,24 @@ class Test extends React.Component {
4961
</button>
5062
<Dialog visible={open} onClose={this.close}>
5163
<div style={{ marginTop: 20, position: 'relative' }}>
52-
<Select
53-
placeholder="placeholder"
54-
style={{ width: 200 }}
55-
getPopupContainer={this.getPopupContainer}
56-
>
57-
<Option value="1">1</Option>
58-
<Option value="2">2</Option>
59-
<Option value="3">3</Option>
60-
</Select>
64+
<MySelect />
6165
</div>
6266
</Dialog>
67+
<div
68+
style={{
69+
transform: 'scale(1.5)',
70+
transformOrigin: '0 0',
71+
display: 'flex',
72+
columnGap: 16,
73+
flexWrap: 'wrap',
74+
}}
75+
>
76+
<h3 style={{ width: '100%' }}>Transform: 150%</h3>
77+
<MySelect />
78+
<MySelect dropdownMatchSelectWidth />
79+
<MySelect dropdownMatchSelectWidth={false} />
80+
<MySelect dropdownMatchSelectWidth={300} />
81+
</div>
6382
</div>
6483
);
6584
}

src/BaseSelect.tsx

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,36 @@ import KeyCode from 'rc-util/lib/KeyCode';
77
import { useComposeRef } from 'rc-util/lib/ref';
88
import type { ScrollConfig, ScrollTo } from 'rc-virtual-list/lib/List';
99
import * as React from 'react';
10+
import { useAllowClear } from './hooks/useAllowClear';
1011
import { BaseSelectContext } from './hooks/useBaseProps';
1112
import useDelayReset from './hooks/useDelayReset';
1213
import useLock from './hooks/useLock';
1314
import useSelectTriggerControl from './hooks/useSelectTriggerControl';
15+
import type {
16+
DisplayInfoType,
17+
DisplayValueType,
18+
Mode,
19+
Placement,
20+
RawValueType,
21+
RenderDOMFunc,
22+
RenderNode,
23+
} from './interface';
1424
import type { RefSelectorProps } from './Selector';
1525
import Selector from './Selector';
1626
import type { RefTriggerProps } from './SelectTrigger';
1727
import SelectTrigger from './SelectTrigger';
1828
import TransBtn from './TransBtn';
1929
import { getSeparatedContent } from './utils/valueUtil';
20-
import type { DisplayInfoType, DisplayValueType, Mode, Placement, RenderDOMFunc, RenderNode, RawValueType } from './interface';
21-
import { useAllowClear } from './hooks/useAllowClear';
2230

23-
export type { DisplayInfoType, DisplayValueType, Mode, Placement, RenderDOMFunc, RenderNode, RawValueType };
31+
export type {
32+
DisplayInfoType,
33+
DisplayValueType,
34+
Mode,
35+
Placement,
36+
RenderDOMFunc,
37+
RenderNode,
38+
RawValueType,
39+
};
2440

2541
const DEFAULT_OMIT_PROPS = [
2642
'value',
@@ -87,10 +103,10 @@ export interface BaseSelectPrivateProps {
87103
searchValue: string,
88104
info: {
89105
source:
90-
| 'typing' //User typing
91-
| 'effect' // Code logic trigger
92-
| 'submit' // tag mode only
93-
| 'blur'; // Not trigger event
106+
| 'typing' //User typing
107+
| 'effect' // Code logic trigger
108+
| 'submit' // tag mode only
109+
| 'blur'; // Not trigger event
94110
},
95111
) => void;
96112
/** Trigger when search text match the `tokenSeparators`. Will provide split content */
@@ -153,8 +169,8 @@ export interface BaseSelectProps extends BaseSelectPrivateProps, React.AriaAttri
153169
// >>> Icons
154170
allowClear?: boolean | { clearIcon?: RenderNode };
155171
suffixIcon?: RenderNode;
156-
/**
157-
* Clear all icon
172+
/**
173+
* Clear all icon
158174
* @deprecated Please use `allowClear` instead
159175
**/
160176
clearIcon?: RenderNode;
@@ -607,24 +623,12 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
607623
};
608624

609625
// ============================ Dropdown ============================
610-
const [containerWidth, setContainerWidth] = React.useState(null);
611-
612626
const [, forceUpdate] = React.useState({});
613627
// We need force update here since popup dom is render async
614628
function onPopupMouseEnter() {
615629
forceUpdate({});
616630
}
617631

618-
useLayoutEffect(() => {
619-
if (triggerOpen) {
620-
// Guaranteed width accuracy
621-
const newWidth = Math.ceil(containerRef.current?.getBoundingClientRect().width);
622-
if (containerWidth !== newWidth && !Number.isNaN(newWidth)) {
623-
setContainerWidth(newWidth);
624-
}
625-
}
626-
}, [triggerOpen]);
627-
628632
// Used for raw custom input trigger
629633
let onTriggerVisibleChange: null | ((newOpen: boolean) => void);
630634
if (customizeRawInputElement) {
@@ -695,22 +699,18 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
695699
onInternalSearch('', false, false);
696700
};
697701

698-
const {
699-
allowClear: mergedAllowClear,
700-
clearIcon: clearNode
701-
} = useAllowClear(
702+
const { allowClear: mergedAllowClear, clearIcon: clearNode } = useAllowClear(
702703
prefixCls,
703704
onClearMouseDown,
704705
displayValues,
705706
allowClear,
706707
clearIcon,
707708
disabled,
708-
709+
709710
mergedSearchValue,
710711
mode,
711712
);
712713

713-
714714
// =========================== OptionList ===========================
715715
const optionList = <OptionList ref={listRef} />;
716716

@@ -736,7 +736,6 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
736736
prefixCls={prefixCls}
737737
visible={triggerOpen}
738738
popupElement={optionList}
739-
containerWidth={containerWidth}
740739
animation={animation}
741740
transitionName={transitionName}
742741
dropdownStyle={dropdownStyle}

src/SelectTrigger.tsx

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ export interface SelectTriggerProps {
6262

6363
animation?: string;
6464
transitionName?: string;
65-
containerWidth: number;
6665
placement?: Placement;
6766
builtinPlacements?: BuildInPlacements;
6867
dropdownStyle: React.CSSProperties;
@@ -90,7 +89,6 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
9089
visible,
9190
children,
9291
popupElement,
93-
containerWidth,
9492
animation,
9593
transitionName,
9694
dropdownStyle,
@@ -124,24 +122,33 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
124122
// ===================== Motion ======================
125123
const mergedTransitionName = animation ? `${dropdownPrefixCls}-${animation}` : transitionName;
126124

125+
// =================== Popup Width ===================
126+
const isNumberPopupWidth = typeof dropdownMatchSelectWidth === 'number';
127+
128+
const stretch = React.useMemo(() => {
129+
if (isNumberPopupWidth) {
130+
return null;
131+
}
132+
133+
return dropdownMatchSelectWidth === false ? 'minWidth' : 'width';
134+
}, [dropdownMatchSelectWidth, isNumberPopupWidth]);
135+
136+
let popupStyle = dropdownStyle;
137+
138+
if (isNumberPopupWidth) {
139+
popupStyle = {
140+
...popupStyle,
141+
width: dropdownMatchSelectWidth,
142+
};
143+
}
144+
127145
// ======================= Ref =======================
128146
const popupRef = React.useRef<HTMLDivElement>(null);
129147

130148
React.useImperativeHandle(ref, () => ({
131149
getPopupElement: () => popupRef.current,
132150
}));
133151

134-
const popupStyle: React.CSSProperties = {
135-
minWidth: containerWidth,
136-
...dropdownStyle,
137-
};
138-
139-
if (typeof dropdownMatchSelectWidth === 'number') {
140-
popupStyle.width = dropdownMatchSelectWidth;
141-
} else if (dropdownMatchSelectWidth) {
142-
popupStyle.width = containerWidth;
143-
}
144-
145152
return (
146153
<Trigger
147154
{...restProps}
@@ -156,6 +163,7 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
156163
{popupNode}
157164
</div>
158165
}
166+
stretch={stretch}
159167
popupAlign={dropdownAlign}
160168
popupVisible={visible}
161169
getPopupContainer={getPopupContainer}

tests/__snapshots__/Select.test.tsx.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
exports[`Select.Basic does not filter when filterOption value is false 1`] = `
44
<div
55
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
6-
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
6+
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
77
>
88
<div>
99
<div
@@ -94,7 +94,7 @@ exports[`Select.Basic does not filter when filterOption value is false 1`] = `
9494
exports[`Select.Basic filterOption could be true as described in default value 1`] = `
9595
<div
9696
class="rc-select-dropdown rc-select-dropdown-empty rc-select-dropdown-placement-bottomLeft"
97-
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
97+
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
9898
>
9999
<div>
100100
<div
@@ -516,7 +516,7 @@ exports[`Select.Basic render should support fieldName 3`] = `
516516
exports[`Select.Basic should contain falsy children 1`] = `
517517
<div
518518
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
519-
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
519+
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
520520
>
521521
<div>
522522
<div
@@ -609,7 +609,7 @@ exports[`Select.Basic should contain falsy children 1`] = `
609609
exports[`Select.Basic should render custom dropdown correctly 1`] = `
610610
<div
611611
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
612-
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
612+
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
613613
>
614614
<div>
615615
<div>

tests/__snapshots__/Tags.test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ exports[`Select.Tags OptGroup renders correctly 1`] = `
101101
</div>
102102
<div
103103
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
104-
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
104+
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
105105
>
106106
<div>
107107
<div

0 commit comments

Comments
 (0)