feat: Select variant (#46379)

* feat: Select variant

* chore: clean

* chore: add test

* chore: update demo
This commit is contained in:
MadCcc 2023-12-11 14:55:58 +08:00 committed by GitHub
parent c588e82a9c
commit 4a07e13685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 496 additions and 470 deletions

View File

@ -4,18 +4,24 @@ type DefaultVariant = 'outlined' | 'borderless';
* Compatible for legacy `bordered` prop, safe to remove after `bordered` is removed.
* @param variant
* @param legacyBordered
* @param variants
*/
const useVariant = <T extends DefaultVariant>(
const useVariant = <T extends string>(
variant: T | undefined,
legacyBordered: boolean | undefined,
): T | DefaultVariant => {
variants: readonly (T | DefaultVariant)[],
): [T | DefaultVariant, boolean] => {
let mergedVariant: T | DefaultVariant;
if (typeof variant !== 'undefined') {
return variant;
mergedVariant = variant;
} else if (legacyBordered === false) {
mergedVariant = 'borderless';
} else {
mergedVariant = 'outlined';
}
if (legacyBordered === false) {
return 'borderless';
}
return 'outlined';
const enableVariantCls = variants.includes(mergedVariant) && mergedVariant !== 'outlined';
return [mergedVariant, enableVariantCls];
};
export default useVariant;

View File

@ -18,7 +18,7 @@ const App: React.FC = () => {
placeholder="Borderless"
onSearch={(text) => setOptions(getPanelValue(text))}
onSelect={globalThis.console.log}
bordered={false}
variant="borderless"
/>
);
};

View File

@ -51,7 +51,7 @@ const ColorInput: FC<ColorInputProps> = (props) => {
<div className={`${colorInputPrefixCls}-container`}>
<Select
value={colorFormat}
bordered={false}
variant="borderless"
getPopupContainer={(current) => current}
popupMatchSelectWidth={68}
placement="bottomRight"

View File

@ -56,8 +56,8 @@ export function triggerFocus(
}
}
export const inputVariants = ['outlined', 'borderless'] as const;
export type InputVariant = (typeof inputVariants)[number];
export const InputVariants = ['outlined', 'borderless'] as const;
export type InputVariant = (typeof InputVariants)[number];
export interface InputProps
extends Omit<
@ -182,8 +182,7 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
mergedAllowClear = { clearIcon: <CloseCircleFilled /> };
}
const variant = useVariant(customVariant, bordered);
const enableVariantCls = inputVariants.includes(variant) && variant !== 'outlined';
const [variant, enableVariantCls] = useVariant(customVariant, bordered, InputVariants);
return wrapCSSVar(
<RcInput

View File

@ -15,7 +15,7 @@ import useSize from '../config-provider/hooks/useSize';
import type { SizeType } from '../config-provider/SizeContext';
import { FormItemInputContext } from '../form/context';
import type { InputFocusOptions, InputVariant } from './Input';
import { inputVariants, triggerFocus } from './Input';
import { InputVariants, triggerFocus } from './Input';
import useStyle from './style';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useVariant from '../_util/hooks/useVariants';
@ -99,8 +99,7 @@ const TextArea = forwardRef<TextAreaRef, TextAreaProps>((props, ref) => {
const cssVarCls = useCSSVarCls(prefixCls);
const [wrapCSSVar, hashId] = useStyle(prefixCls, cssVarCls);
const variant = useVariant(customVariant, bordered);
const enableVariantCls = variant !== 'outlined' && inputVariants.includes(variant);
const [variant, enableVariantCls] = useVariant(customVariant, bordered, InputVariants);
return wrapCSSVar(
<RcTextArea

View File

@ -984,299 +984,6 @@ exports[`renders components/select/demo/basic.tsx extend context correctly 1`] =
exports[`renders components/select/demo/basic.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/bordered.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
style="flex-wrap: wrap;"
>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow"
style="width: 120px;"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="Lucy"
>
Lucy
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="Jack"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
jack
</div>
<div
aria-label="Lucy"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_1"
role="option"
>
lucy
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
title="Jack"
>
<div
class="ant-select-item-option-content"
>
Jack
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-selected"
title="Lucy"
>
<div
class="ant-select-item-option-content"
>
Lucy
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="yiminghe"
>
<div
class="ant-select-item-option-content"
>
yiminghe
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow ant-select-disabled"
style="width: 120px;"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
disabled=""
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="Lucy"
>
Lucy
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="Lucy"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
lucy
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
title="Lucy"
>
<div
class="ant-select-item-option-content"
>
Lucy
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
`;
exports[`renders components/select/demo/bordered.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/coordinate.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
@ -12417,3 +12124,294 @@ exports[`renders components/select/demo/tags.tsx extend context correctly 1`] =
`;
exports[`renders components/select/demo/tags.tsx extend context correctly 2`] = `[]`;
exports[`renders components/select/demo/variant.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
style="flex-wrap: wrap;"
>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow"
style="width: 120px;"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="Jack"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
jack
</div>
<div
aria-label="Lucy"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
role="option"
>
lucy
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
title="Jack"
>
<div
class="ant-select-item-option-content"
>
Jack
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="Lucy"
>
<div
class="ant-select-item-option-content"
>
Lucy
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option"
title="yiminghe"
>
<div
class="ant-select-item-option-content"
>
yiminghe
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow ant-select-disabled"
style="width: 120px;"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="rc_select_TEST_OR_SSR_list"
autocomplete="off"
class="ant-select-selection-search-input"
disabled=""
id="rc_select_TEST_OR_SSR"
readonly=""
role="combobox"
style="opacity: 0;"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<div
class="ant-select-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up ant-select-dropdown-placement-bottomLeft"
style="--arrow-x: 0px; --arrow-y: 0px; left: -1000vw; top: -1000vh; box-sizing: border-box;"
>
<div>
<div
id="rc_select_TEST_OR_SSR_list"
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-label="Lucy"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
lucy
</div>
</div>
<div
class="rc-virtual-list"
style="position: relative;"
>
<div
class="rc-virtual-list-holder"
style="max-height: 256px; overflow-y: auto;"
>
<div>
<div
class="rc-virtual-list-holder-inner"
style="display: flex; flex-direction: column;"
>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-active"
title="Lucy"
>
<div
class="ant-select-item-option-content"
>
Lucy
</div>
<span
aria-hidden="true"
class="ant-select-item-option-state"
style="user-select: none;"
unselectable="on"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select: none;"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
`;
exports[`renders components/select/demo/variant.tsx extend context correctly 2`] = `[]`;

View File

@ -502,143 +502,6 @@ Array [
]
`;
exports[`renders components/select/demo/bordered.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
style="flex-wrap:wrap"
>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow"
style="width:120px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="Lucy"
>
Lucy
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow ant-select-disabled"
style="width:120px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
disabled=""
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-item"
title="Lucy"
>
Lucy
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
`;
exports[`renders components/select/demo/coordinate.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
@ -4003,3 +3866,138 @@ exports[`renders components/select/demo/tags.tsx correctly 1`] = `
</span>
</div>
`;
exports[`renders components/select/demo/variant.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"
style="flex-wrap:wrap"
>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow"
style="width:120px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-select-borderless ant-select-single ant-select-show-arrow ant-select-disabled"
style="width:120px"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-expanded="false"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
disabled=""
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Borderless
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
`;

View File

@ -172,5 +172,18 @@ describe('Select', () => {
errSpy.mockRestore();
});
it('deprecate bordered', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const { container } = render(<Select bordered={false} />);
expect(errSpy).toHaveBeenCalledWith(
expect.stringContaining('Warning: [antd: Select] `bordered` is deprecated'),
);
expect(container.querySelector('.ant-select-borderless')).toBeTruthy();
errSpy.mockRestore();
});
});
});

View File

@ -1,7 +0,0 @@
## zh-CN
无边框样式。
## en-US
Bordered-less style component.

View File

@ -0,0 +1,7 @@
## zh-CN
形态变体
## en-US
Variants of Select.

View File

@ -4,9 +4,9 @@ import { Select, Space } from 'antd';
const App: React.FC = () => (
<Space wrap>
<Select
defaultValue="lucy"
placeholder="Borderless"
style={{ width: 120 }}
bordered={false}
variant="borderless"
options={[
{ value: 'jack', label: 'Jack' },
{ value: 'lucy', label: 'Lucy' },
@ -14,10 +14,10 @@ const App: React.FC = () => (
]}
/>
<Select
defaultValue="lucy"
placeholder="Borderless"
style={{ width: 120 }}
disabled
bordered={false}
variant="borderless"
options={[{ value: 'lucy', label: 'Lucy' }]}
/>
</Space>

View File

@ -35,7 +35,7 @@ Select component to select value from options.
<code src="./demo/suffix.tsx" debug>Suffix</code>
<code src="./demo/custom-dropdown-menu.tsx">Custom dropdown</code>
<code src="./demo/hide-selected.tsx">Hide Already Selected</code>
<code src="./demo/bordered.tsx">Bordered-less</code>
<code src="./demo/variant.tsx">Variants</code>
<code src="./demo/custom-tag-render.tsx">Custom Tag Render</code>
<code src="./demo/responsive.tsx">Responsive maxTagCount</code>
<code src="./demo/big-data.tsx">Big Data</code>
@ -59,7 +59,6 @@ Common props ref[Common props](/docs/react/common-props)
| allowClear | Customize clear icon | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: Support object type |
| autoClearSearchValue | Whether the current search will be cleared on selecting an item. Only applies when `mode` is set to `multiple` or `tags` | boolean | true | |
| autoFocus | Get focus by default | boolean | false | |
| bordered | Whether has border style | boolean | true | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
| defaultOpen | Initial open state of dropdown | boolean | - | |
| defaultValue | Initial selected option | string \| string\[] \| <br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
@ -97,6 +96,7 @@ Common props ref[Common props](/docs/react/common-props)
| tagRender | Customize tag render, only applies when `mode` is set to `multiple` or `tags` | (props) => ReactNode | - | |
| tokenSeparators | Separator used to tokenize, only applies when `mode="tags"` | string\[] | - | |
| value | Current selected option (considered as a immutable array) | string \| string\[] \| <br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
| variant | Variants of Input | `outlined` \| `borderless` | `outlined` | 5.13.0 |
| virtual | Disable virtual scroll when set to false | boolean | true | 4.1.0 |
| onBlur | Called when blur | function | - | |
| onChange | Called when select an option or input value change | function(value, option:Option \| Array&lt;Option>) | - | |

View File

@ -26,6 +26,7 @@ import useBuiltinPlacements from './useBuiltinPlacements';
import useIcons from './useIcons';
import useShowArrow from './useShowArrow';
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
import useVariants from '../_util/hooks/useVariants';
type RawValue = string | number;
@ -39,6 +40,9 @@ export interface LabeledValue {
export type SelectValue = RawValue | RawValue[] | LabeledValue | LabeledValue[] | undefined;
const SelectVariants = ['outlined', 'borderless'] as const;
export type SelectVariant = (typeof SelectVariants)[number];
export interface InternalSelectProps<
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
@ -48,12 +52,15 @@ export interface InternalSelectProps<
size?: SizeType;
disabled?: boolean;
mode?: 'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE' | 'combobox';
/** @deprecated Use `variant` instead. */
bordered?: boolean;
/**
* @deprecated `showArrow` is deprecated which will be removed in next major version. It will be a
* default behavior, you can hide it by setting `suffixIcon` to null.
*/
showArrow?: boolean;
/** @default `outlined` */
variant?: SelectVariant;
}
export interface SelectProps<
@ -80,7 +87,10 @@ const InternalSelect = <
ValueType = any,
OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType,
>(
{
props: SelectProps<ValueType, OptionType>,
ref: React.Ref<BaseSelectRef>,
) => {
const {
prefixCls: customizePrefixCls,
bordered = true,
className,
@ -101,10 +111,10 @@ const InternalSelect = <
direction: propDirection,
style,
allowClear,
...props
}: SelectProps<ValueType, OptionType>,
ref: React.Ref<BaseSelectRef>,
) => {
variant: customizeVariant,
...rest
} = props;
const {
getPopupContainer: getContextPopupContainer,
getPrefixCls,
@ -122,6 +132,8 @@ const InternalSelect = <
const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction);
const [variant, enableVariantCls] = useVariants(customizeVariant, bordered, SelectVariants);
const rootCls = useCSSVarCls(prefixCls);
const [wrapCSSVar, hashId] = useStyle(prefixCls, rootCls);
@ -166,19 +178,18 @@ const InternalSelect = <
// ===================== Icons =====================
const { suffixIcon, itemIcon, removeIcon, clearIcon } = useIcons({
...props,
...rest,
multiple: isMultiple,
hasFeedback,
feedbackIcon,
showSuffixIcon,
prefixCls,
showArrow: props.showArrow,
componentName: 'Select',
});
const mergedAllowClear = allowClear === true ? { clearIcon } : allowClear;
const selectProps = omit(props as typeof props & { itemIcon: React.ReactNode }, [
const selectProps = omit(rest as typeof rest & { itemIcon: React.ReactNode }, [
'suffixIcon',
'itemIcon',
]);
@ -204,7 +215,7 @@ const InternalSelect = <
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-${variant}`]: enableVariantCls,
[`${prefixCls}-in-form-item`]: isFormItemInput,
},
getStatusClassNames(prefixCls, mergedStatus, hasFeedback),
@ -243,6 +254,8 @@ const InternalSelect = <
'deprecated',
'`showArrow` is deprecated which will be removed in next major version. It will be a default behavior, you can hide it by setting `suffixIcon` to null.',
);
warning.deprecated(!('bordered' in props), 'bordered', 'variant');
}
// ====================== zIndex =========================

View File

@ -36,7 +36,7 @@ demo:
<code src="./demo/suffix.tsx" debug>后缀图标</code>
<code src="./demo/custom-dropdown-menu.tsx">扩展菜单</code>
<code src="./demo/hide-selected.tsx">隐藏已选择选项</code>
<code src="./demo/bordered.tsx">无边框</code>
<code src="./demo/variant.tsx">形态变体</code>
<code src="./demo/custom-tag-render.tsx">自定义选择标签</code>
<code src="./demo/responsive.tsx">响应式 maxTagCount</code>
<code src="./demo/big-data.tsx">大数据</code>
@ -60,7 +60,6 @@ demo:
| allowClear | 自定义清除按钮 | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: 支持对象类型 |
| autoClearSearchValue | 是否在选中项后清空搜索框,只在 `mode``multiple``tags` 时有效 | boolean | true | |
| autoFocus | 默认获取焦点 | boolean | false | |
| bordered | 是否有边框 | boolean | true | |
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |
| defaultValue | 指定默认选中的条目 | string \| string\[] \|<br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
@ -98,6 +97,7 @@ demo:
| tagRender | 自定义 tag 内容 render仅在 `mode``multiple``tags` 时生效 | (props) => ReactNode | - | |
| tokenSeparators | 自动分词的分隔符,仅在 `mode="tags"` 时生效 | string\[] | - | |
| value | 指定当前选中的条目多选时为一个数组。value 数组引用未变化时Select 不会更新) | string \| string\[] \| <br />number \| number\[] \| <br />LabeledValue \| LabeledValue\[] | - | |
| variant | 形态变体 | `outlined` \| `borderless` | `outlined` | 5.13.0 |
| virtual | 设置 false 时关闭虚拟滚动 | boolean | true | 4.1.0 |
| onBlur | 失去焦点时回调 | function | - | |
| onChange | 选中 option或 input 的 value 变化时,调用此函数 | function(value, option:Option \| Array&lt;Option>) | - | |