Skip to content

Commit

Permalink
refactor: Select use @rc-component/trigger align logic instead of s…
Browse files Browse the repository at this point in the history
…elf measure (#976)

* chore: use trigger stretch

* test: update snapshot
  • Loading branch information
zombieJ committed Aug 23, 2023
1 parent 2decf05 commit a64b6ba
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 60 deletions.
47 changes: 33 additions & 14 deletions docs/examples/getPopupContainer.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import '../../assets/index.less';
import 'rc-dialog/assets/index.css';
import '../../assets/index.less';

import Dialog from 'rc-dialog';
import Select, { type SelectProps } from 'rc-select';
import React from 'react';
import Select, { Option } from 'rc-select';

const MySelect = (props: Partial<SelectProps>) => (
<Select
placeholder="placeholder"
style={{ width: 100 }}
getPopupContainer={(node) => node.parentNode}
options={new Array(3).fill(null).map((_, index) => ({
value: index,
label: `long_label_${index}`,
}))}
{...props}
/>
);

class Test extends React.Component {
state = {
open: false,
destroy: false,
};

getPopupContainer = node => node.parentNode;

setVisible = open => {
setVisible = (open) => {
this.setState({
open,
});
Expand All @@ -38,6 +49,7 @@ class Test extends React.Component {
if (destroy) {
return null;
}

return (
<div>
<button type="button" onClick={this.open}>
Expand All @@ -49,17 +61,24 @@ class Test extends React.Component {
</button>
<Dialog visible={open} onClose={this.close}>
<div style={{ marginTop: 20, position: 'relative' }}>
<Select
placeholder="placeholder"
style={{ width: 200 }}
getPopupContainer={this.getPopupContainer}
>
<Option value="1">1</Option>
<Option value="2">2</Option>
<Option value="3">3</Option>
</Select>
<MySelect />
</div>
</Dialog>
<div
style={{
transform: 'scale(1.5)',
transformOrigin: '0 0',
display: 'flex',
columnGap: 16,
flexWrap: 'wrap',
}}
>
<h3 style={{ width: '100%' }}>Transform: 150%</h3>
<MySelect />
<MySelect dropdownMatchSelectWidth />
<MySelect dropdownMatchSelectWidth={false} />
<MySelect dropdownMatchSelectWidth={300} />
</div>
</div>
);
}
Expand Down
55 changes: 27 additions & 28 deletions src/BaseSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,36 @@ import KeyCode from 'rc-util/lib/KeyCode';
import { useComposeRef } from 'rc-util/lib/ref';
import type { ScrollConfig, ScrollTo } from 'rc-virtual-list/lib/List';
import * as React from 'react';
import { useAllowClear } from './hooks/useAllowClear';
import { BaseSelectContext } from './hooks/useBaseProps';
import useDelayReset from './hooks/useDelayReset';
import useLock from './hooks/useLock';
import useSelectTriggerControl from './hooks/useSelectTriggerControl';
import type {
DisplayInfoType,
DisplayValueType,
Mode,
Placement,
RawValueType,
RenderDOMFunc,
RenderNode,
} from './interface';
import type { RefSelectorProps } from './Selector';
import Selector from './Selector';
import type { RefTriggerProps } from './SelectTrigger';
import SelectTrigger from './SelectTrigger';
import TransBtn from './TransBtn';
import { getSeparatedContent } from './utils/valueUtil';
import type { DisplayInfoType, DisplayValueType, Mode, Placement, RenderDOMFunc, RenderNode, RawValueType } from './interface';
import { useAllowClear } from './hooks/useAllowClear';

export type { DisplayInfoType, DisplayValueType, Mode, Placement, RenderDOMFunc, RenderNode, RawValueType };
export type {
DisplayInfoType,
DisplayValueType,
Mode,
Placement,
RenderDOMFunc,
RenderNode,
RawValueType,
};

const DEFAULT_OMIT_PROPS = [
'value',
Expand Down Expand Up @@ -87,10 +103,10 @@ export interface BaseSelectPrivateProps {
searchValue: string,
info: {
source:
| 'typing' //User typing
| 'effect' // Code logic trigger
| 'submit' // tag mode only
| 'blur'; // Not trigger event
| 'typing' //User typing
| 'effect' // Code logic trigger
| 'submit' // tag mode only
| 'blur'; // Not trigger event
},
) => void;
/** Trigger when search text match the `tokenSeparators`. Will provide split content */
Expand Down Expand Up @@ -153,8 +169,8 @@ export interface BaseSelectProps extends BaseSelectPrivateProps, React.AriaAttri
// >>> Icons
allowClear?: boolean | { clearIcon?: RenderNode };
suffixIcon?: RenderNode;
/**
* Clear all icon
/**
* Clear all icon
* @deprecated Please use `allowClear` instead
**/
clearIcon?: RenderNode;
Expand Down Expand Up @@ -607,24 +623,12 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
};

// ============================ Dropdown ============================
const [containerWidth, setContainerWidth] = React.useState(null);

const [, forceUpdate] = React.useState({});
// We need force update here since popup dom is render async
function onPopupMouseEnter() {
forceUpdate({});
}

useLayoutEffect(() => {
if (triggerOpen) {
// Guaranteed width accuracy
const newWidth = Math.ceil(containerRef.current?.getBoundingClientRect().width);
if (containerWidth !== newWidth && !Number.isNaN(newWidth)) {
setContainerWidth(newWidth);
}
}
}, [triggerOpen]);

// Used for raw custom input trigger
let onTriggerVisibleChange: null | ((newOpen: boolean) => void);
if (customizeRawInputElement) {
Expand Down Expand Up @@ -695,22 +699,18 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
onInternalSearch('', false, false);
};

const {
allowClear: mergedAllowClear,
clearIcon: clearNode
} = useAllowClear(
const { allowClear: mergedAllowClear, clearIcon: clearNode } = useAllowClear(
prefixCls,
onClearMouseDown,
displayValues,
allowClear,
clearIcon,
disabled,

mergedSearchValue,
mode,
);


// =========================== OptionList ===========================
const optionList = <OptionList ref={listRef} />;

Expand All @@ -736,7 +736,6 @@ const BaseSelect = React.forwardRef((props: BaseSelectProps, ref: React.Ref<Base
prefixCls={prefixCls}
visible={triggerOpen}
popupElement={optionList}
containerWidth={containerWidth}
animation={animation}
transitionName={transitionName}
dropdownStyle={dropdownStyle}
Expand Down
34 changes: 21 additions & 13 deletions src/SelectTrigger.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ export interface SelectTriggerProps {

animation?: string;
transitionName?: string;
containerWidth: number;
placement?: Placement;
builtinPlacements?: BuildInPlacements;
dropdownStyle: React.CSSProperties;
Expand Down Expand Up @@ -90,7 +89,6 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
visible,
children,
popupElement,
containerWidth,
animation,
transitionName,
dropdownStyle,
Expand Down Expand Up @@ -124,24 +122,33 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
// ===================== Motion ======================
const mergedTransitionName = animation ? `${dropdownPrefixCls}-${animation}` : transitionName;

// =================== Popup Width ===================
const isNumberPopupWidth = typeof dropdownMatchSelectWidth === 'number';

const stretch = React.useMemo(() => {
if (isNumberPopupWidth) {
return null;
}

return dropdownMatchSelectWidth === false ? 'minWidth' : 'width';
}, [dropdownMatchSelectWidth, isNumberPopupWidth]);

let popupStyle = dropdownStyle;

if (isNumberPopupWidth) {
popupStyle = {
...popupStyle,
width: dropdownMatchSelectWidth,
};
}

// ======================= Ref =======================
const popupRef = React.useRef<HTMLDivElement>(null);

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

const popupStyle: React.CSSProperties = {
minWidth: containerWidth,
...dropdownStyle,
};

if (typeof dropdownMatchSelectWidth === 'number') {
popupStyle.width = dropdownMatchSelectWidth;
} else if (dropdownMatchSelectWidth) {
popupStyle.width = containerWidth;
}

return (
<Trigger
{...restProps}
Expand All @@ -156,6 +163,7 @@ const SelectTrigger: React.RefForwardingComponent<RefTriggerProps, SelectTrigger
{popupNode}
</div>
}
stretch={stretch}
popupAlign={dropdownAlign}
popupVisible={visible}
getPopupContainer={getPopupContainer}
Expand Down
8 changes: 4 additions & 4 deletions tests/__snapshots__/Select.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Select.Basic does not filter when filterOption value is false 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
Expand Down Expand Up @@ -94,7 +94,7 @@ exports[`Select.Basic does not filter when filterOption value is false 1`] = `
exports[`Select.Basic filterOption could be true as described in default value 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-empty rc-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
Expand Down Expand Up @@ -516,7 +516,7 @@ exports[`Select.Basic render should support fieldName 3`] = `
exports[`Select.Basic should contain falsy children 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
Expand Down Expand Up @@ -609,7 +609,7 @@ exports[`Select.Basic should contain falsy children 1`] = `
exports[`Select.Basic should render custom dropdown correctly 1`] = `
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div>
Expand Down
2 changes: 1 addition & 1 deletion tests/__snapshots__/Tags.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ exports[`Select.Tags OptGroup renders correctly 1`] = `
</div>
<div
class="rc-select-dropdown rc-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box; min-width: 0; width: 0px;"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
Expand Down

0 comments on commit a64b6ba

Please sign in to comment.