Browse Source

refactor:select (#6295)

* refactor:select

* update doc

* delete useless
pull/6296/head^2
果冻橙 2 years ago committed by GitHub
parent
commit
39e5824699
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      components/select/index.en-US.md
  2. 48
      components/select/index.tsx
  3. 6
      components/select/index.zh-CN.md
  4. 166
      components/select/style/dropdown.tsx
  5. 345
      components/select/style/index.tsx
  6. 239
      components/select/style/multiple.tsx
  7. 192
      components/select/style/single.tsx
  8. 2
      components/style.ts
  9. 4
      components/theme/interface/components.ts

2
components/select/index.en-US.md

@ -2,7 +2,7 @@
category: Components
type: Data Entry
title: Select
cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*zo76T7KQx2UAAAAAAAAAAAAADrJ8AQ/original
---
Select component to select value from options.

48
components/select/index.tsx

@ -1,4 +1,4 @@
import type { App, PropType, Plugin, ExtractPropTypes } from 'vue';
import type { App, Plugin, ExtractPropTypes } from 'vue';
import { computed, defineComponent, ref } from 'vue';
import classNames from '../_util/classNames';
import type { BaseSelectRef } from '../vc-select';
@ -16,6 +16,10 @@ import type { SizeType } from '../config-provider';
import { initDefaultProps } from '../_util/props-util';
import type { InputStatus } from '../_util/statusUtils';
import { getStatusClassNames, getMergedStatus } from '../_util/statusUtils';
import { stringType, someType, functionType, booleanType } from '../_util/type';
// CSSINJS
import useStyle from './style';
type RawValue = string | number;
@ -37,23 +41,19 @@ export const selectProps = () => ({
'getRawInputElement',
'backfill',
]),
value: {
type: [Array, Object, String, Number] as PropType<SelectValue>,
},
defaultValue: {
type: [Array, Object, String, Number] as PropType<SelectValue>,
},
value: someType<SelectValue>([Array, Object, String, Number]),
defaultValue: someType<SelectValue>([Array, Object, String, Number]),
notFoundContent: PropTypes.any,
suffixIcon: PropTypes.any,
itemIcon: PropTypes.any,
size: String as PropType<SizeType>,
mode: String as PropType<'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE'>,
bordered: { type: Boolean, default: true },
size: stringType<SizeType>(),
mode: stringType<'multiple' | 'tags' | 'SECRET_COMBOBOX_MODE_DO_NOT_USE'>(),
bordered: booleanType(true),
transitionName: String,
choiceTransitionName: { type: String, default: '' },
placement: String as PropType<SelectCommonPlacement>,
status: String as PropType<InputStatus>,
'onUpdate:value': Function as PropType<(val: SelectValue) => void>,
choiceTransitionName: stringType(''),
placement: stringType<SelectCommonPlacement>(),
status: stringType<InputStatus>(),
'onUpdate:value': functionType<(val: SelectValue) => void>(),
});
export type SelectProps = Partial<ExtractPropTypes<ReturnType<typeof selectProps>>>;
@ -123,6 +123,10 @@ const Select = defineComponent({
getPrefixCls,
getPopupContainer,
} = useConfigInject('select', props);
// style
const [wrapSSR, hashId] = useStyle(prefixCls);
const rootPrefixCls = computed(() => getPrefixCls());
// ===================== Placement =====================
const placement = computed(() => {
@ -150,6 +154,7 @@ const Select = defineComponent({
[`${prefixCls.value}-in-form-item`]: formItemInputContext.isFormItemInput,
},
getStatusClassNames(prefixCls.value, mergedStatus.value, formItemInputContext.hasFeedback),
hashId.value,
),
);
const triggerChange: SelectProps['onChange'] = (...args) => {
@ -224,10 +229,15 @@ const Select = defineComponent({
'status',
]);
const rcSelectRtlDropdownClassName = classNames(dropdownClassName, {
[`${prefixCls.value}-dropdown-${direction.value}`]: direction.value === 'rtl',
});
return (
const rcSelectRtlDropdownClassName = classNames(
dropdownClassName,
{
[`${prefixCls.value}-dropdown-${direction.value}`]: direction.value === 'rtl',
},
hashId.value,
);
return wrapSSR(
<RcSelect
ref={selectRef}
virtual={virtual}
@ -259,7 +269,7 @@ const Select = defineComponent({
optionLabelRender={slots.optionLabel}
maxTagPlaceholder={props.maxTagPlaceholder || slots.maxTagPlaceholder}
showArrow={hasFeedback || showArrow}
></RcSelect>
></RcSelect>,
);
};
},

6
components/select/index.zh-CN.md

@ -3,7 +3,7 @@ category: Components
subtitle: 选择器
type: 数据录入
title: Select
cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*zo76T7KQx2UAAAAAAAAAAAAADrJ8AQ/original
---
下拉选择器。
@ -60,8 +60,8 @@ cover: https://gw.alipayobjects.com/zos/alicdn/_0XzgOis7/Select.svg
| placement | 选择框弹出的位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | bottomLeft | 3.3.0 |
| removeIcon | 自定义的多选框清除图标 | VNode \| slot | - | |
| searchValue | 控制搜索文本 | string | - | |
| showArrow | 是否显示下拉小箭头 | boolean | 单选为true,多选为false | |
| showSearch | 配置是否可搜索 | boolean | 单选为false,多选为true | |
| showArrow | 是否显示下拉小箭头 | boolean | 单选为 true,多选为 false | |
| showSearch | 配置是否可搜索 | boolean | 单选为 false,多选为 true | |
| size | 选择框大小,可选 `large` `small` | string | default | |
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
| suffixIcon | 自定义的选择框后缀图标 | VNode \| slot | - | |

166
components/select/style/dropdown.tsx

@ -0,0 +1,166 @@
import type { CSSObject } from '../../_util/cssinjs';
import type { SelectToken } from '.';
import {
initMoveMotion,
initSlideMotion,
slideDownIn,
slideDownOut,
slideUpIn,
slideUpOut,
} from '../../_style/motion';
import type { GenerateStyle } from '../../theme/internal';
import { resetComponent, textEllipsis } from '../../_style';
const genItemStyle: GenerateStyle<SelectToken, CSSObject> = token => {
const { controlPaddingHorizontal } = token;
return {
position: 'relative',
display: 'block',
minHeight: token.controlHeight,
padding: `${
(token.controlHeight - token.fontSize * token.lineHeight) / 2
}px ${controlPaddingHorizontal}px`,
color: token.colorText,
fontWeight: 'normal',
fontSize: token.fontSize,
lineHeight: token.lineHeight,
boxSizing: 'border-box',
};
};
const genSingleStyle: GenerateStyle<SelectToken> = token => {
const { antCls, componentCls } = token;
const selectItemCls = `${componentCls}-item`;
return [
{
[`${componentCls}-dropdown`]: {
// ========================== Popup ==========================
...resetComponent(token),
position: 'absolute',
top: -9999,
zIndex: token.zIndexPopup,
boxSizing: 'border-box',
padding: token.paddingXXS,
overflow: 'hidden',
fontSize: token.fontSize,
// Fix select render lag of long text in chrome
// https://github.com/ant-design/ant-design/issues/11456
// https://github.com/ant-design/ant-design/issues/11843
fontVariant: 'initial',
backgroundColor: token.colorBgElevated,
borderRadius: token.borderRadiusLG,
outline: 'none',
boxShadow: token.boxShadowSecondary,
[`
&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-dropdown-placement-bottomLeft,
&${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-dropdown-placement-bottomLeft
`]: {
animationName: slideUpIn,
},
[`
&${antCls}-slide-up-enter${antCls}-slide-up-enter-active${componentCls}-dropdown-placement-topLeft,
&${antCls}-slide-up-appear${antCls}-slide-up-appear-active${componentCls}-dropdown-placement-topLeft
`]: {
animationName: slideDownIn,
},
[`&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-dropdown-placement-bottomLeft`]:
{
animationName: slideUpOut,
},
[`&${antCls}-slide-up-leave${antCls}-slide-up-leave-active${componentCls}-dropdown-placement-topLeft`]:
{
animationName: slideDownOut,
},
'&-hidden': {
display: 'none',
},
'&-empty': {
color: token.colorTextDisabled,
},
// ========================= Options =========================
[`${selectItemCls}-empty`]: {
...genItemStyle(token),
color: token.colorTextDisabled,
},
[`${selectItemCls}`]: {
...genItemStyle(token),
cursor: 'pointer',
transition: `background ${token.motionDurationSlow} ease`,
borderRadius: token.borderRadiusSM,
// =========== Group ============
'&-group': {
color: token.colorTextDescription,
fontSize: token.fontSizeSM,
cursor: 'default',
},
// =========== Option ===========
'&-option': {
display: 'flex',
'&-content': {
flex: 'auto',
...textEllipsis,
},
'&-state': {
flex: 'none',
},
[`&-active:not(${selectItemCls}-option-disabled)`]: {
backgroundColor: token.controlItemBgHover,
},
[`&-selected:not(${selectItemCls}-option-disabled)`]: {
color: token.colorText,
fontWeight: token.fontWeightStrong,
backgroundColor: token.controlItemBgActive,
[`${selectItemCls}-option-state`]: {
color: token.colorPrimary,
},
},
'&-disabled': {
[`&${selectItemCls}-option-selected`]: {
backgroundColor: token.colorBgContainerDisabled,
},
color: token.colorTextDisabled,
cursor: 'not-allowed',
},
'&-grouped': {
paddingInlineStart: token.controlPaddingHorizontal * 2,
},
},
},
// =========================== RTL ===========================
'&-rtl': {
direction: 'rtl',
},
},
},
// Follow code may reuse in other components
initSlideMotion(token, 'slide-up'),
initSlideMotion(token, 'slide-down'),
initMoveMotion(token, 'move-up'),
initMoveMotion(token, 'move-down'),
];
};
export default genSingleStyle;

345
components/select/style/index.tsx

@ -1,7 +1,342 @@
import '../../style/index.less';
import './index.less';
import type { CSSObject } from '../../_util/cssinjs';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import genDropdownStyle from './dropdown';
import genMultipleStyle from './multiple';
import genSingleStyle from './single';
import { resetComponent, resetIcon, textEllipsis } from '../../_style';
import { genCompactItemStyle } from '../../_style/compact-item';
// style dependencies
import '../../empty/style';
export interface ComponentToken {
zIndexPopup: number;
}
// deps-lint-skip: form
export interface SelectToken extends FullToken<'Select'> {
rootPrefixCls: string;
inputPaddingHorizontalBase: number;
}
// ============================= Selector =============================
const genSelectorStyle: GenerateStyle<SelectToken, CSSObject> = token => {
const { componentCls } = token;
return {
position: 'relative',
backgroundColor: token.colorBgContainer,
border: `${token.lineWidth}px ${token.lineType} ${token.colorBorder}`,
transition: `all ${token.motionDurationMid} ${token.motionEaseInOut}`,
input: {
cursor: 'pointer',
},
[`${componentCls}-show-search&`]: {
cursor: 'text',
input: {
cursor: 'auto',
color: 'inherit',
},
},
[`${componentCls}-disabled&`]: {
color: token.colorTextDisabled,
background: token.colorBgContainerDisabled,
cursor: 'not-allowed',
[`${componentCls}-multiple&`]: {
background: token.colorBgContainerDisabled,
},
input: {
cursor: 'not-allowed',
},
},
};
};
// ============================== Status ==============================
const genStatusStyle = (
rootSelectCls: string,
token: {
componentCls: string;
antCls: string;
borderHoverColor: string;
outlineColor: string;
controlOutlineWidth: number;
controlLineWidth: number;
},
overwriteDefaultBorder: boolean = false,
): CSSObject => {
const { componentCls, borderHoverColor, outlineColor, antCls } = token;
const overwriteStyle: CSSObject = overwriteDefaultBorder
? {
[`${componentCls}-selector`]: {
borderColor: borderHoverColor,
},
}
: {};
return {
[rootSelectCls]: {
[`&:not(${componentCls}-disabled):not(${componentCls}-customize-input):not(${antCls}-pagination-size-changer)`]:
{
...overwriteStyle,
[`${componentCls}-focused& ${componentCls}-selector`]: {
borderColor: borderHoverColor,
boxShadow: `0 0 0 ${token.controlOutlineWidth}px ${outlineColor}`,
borderInlineEndWidth: `${token.controlLineWidth}px !important`,
outline: 0,
},
[`&:hover ${componentCls}-selector`]: {
borderColor: borderHoverColor,
borderInlineEndWidth: `${token.controlLineWidth}px !important`,
},
},
},
};
};
// ============================== Styles ==============================
// /* Reset search input style */
const getSearchInputWithoutBorderStyle: GenerateStyle<SelectToken, CSSObject> = token => {
const { componentCls } = token;
return {
[`${componentCls}-selection-search-input`]: {
margin: 0,
padding: 0,
background: 'transparent',
border: 'none',
outline: 'none',
appearance: 'none',
'&::-webkit-search-cancel-button': {
display: 'none',
'-webkit-appearance': 'none',
},
},
};
};
// =============================== Base ===============================
const genBaseStyle: GenerateStyle<SelectToken> = token => {
const { componentCls, inputPaddingHorizontalBase, iconCls } = token;
return {
[componentCls]: {
...resetComponent(token),
position: 'relative',
display: 'inline-block',
cursor: 'pointer',
[`&:not(${componentCls}-customize-input) ${componentCls}-selector`]: {
...genSelectorStyle(token),
...getSearchInputWithoutBorderStyle(token),
},
// [`&:not(&-disabled):hover ${selectCls}-selector`]: {
// ...genHoverStyle(token),
// },
// ======================== Selection ========================
[`${componentCls}-selection-item`]: {
flex: 1,
fontWeight: 'normal',
...textEllipsis,
},
// ======================= Placeholder =======================
[`${componentCls}-selection-placeholder`]: {
...textEllipsis,
flex: 1,
color: token.colorTextPlaceholder,
pointerEvents: 'none',
},
// ========================== Arrow ==========================
[`${componentCls}-arrow`]: {
...resetIcon(),
position: 'absolute',
top: '50%',
insetInlineStart: 'auto',
insetInlineEnd: inputPaddingHorizontalBase,
height: token.fontSizeIcon,
marginTop: -token.fontSizeIcon / 2,
color: token.colorTextQuaternary,
fontSize: token.fontSizeIcon,
lineHeight: 1,
textAlign: 'center',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
[iconCls]: {
verticalAlign: 'top',
transition: `transform ${token.motionDurationSlow}`,
'> svg': {
verticalAlign: 'top',
},
[`&:not(${componentCls}-suffix)`]: {
pointerEvents: 'auto',
},
},
[`${componentCls}-disabled &`]: {
cursor: 'not-allowed',
},
'> *:not(:last-child)': {
marginInlineEnd: 8, // FIXME: magic
},
},
// ========================== Clear ==========================
[`${componentCls}-clear`]: {
position: 'absolute',
top: '50%',
insetInlineStart: 'auto',
insetInlineEnd: inputPaddingHorizontalBase,
zIndex: 1,
display: 'inline-block',
width: token.fontSizeIcon,
height: token.fontSizeIcon,
marginTop: -token.fontSizeIcon / 2,
color: token.colorTextQuaternary,
fontSize: token.fontSizeIcon,
fontStyle: 'normal',
lineHeight: 1,
textAlign: 'center',
textTransform: 'none',
background: token.colorBgContainer,
cursor: 'pointer',
opacity: 0,
transition: `color ${token.motionDurationMid} ease, opacity ${token.motionDurationSlow} ease`,
textRendering: 'auto',
'&:before': {
display: 'block',
},
'&:hover': {
color: token.colorTextTertiary,
},
},
'&:hover': {
[`${componentCls}-clear`]: {
opacity: 1,
},
},
},
// ========================= Feedback ==========================
[`${componentCls}-has-feedback`]: {
[`${componentCls}-clear`]: {
insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXXS,
},
},
};
};
// ============================== Styles ==============================
const genSelectStyle: GenerateStyle<SelectToken> = token => {
const { componentCls } = token;
return [
{
[componentCls]: {
// ==================== BorderLess ====================
[`&-borderless ${componentCls}-selector`]: {
backgroundColor: `transparent !important`,
borderColor: `transparent !important`,
boxShadow: `none !important`,
},
// ==================== In Form ====================
[`&${componentCls}-in-form-item`]: {
width: '100%',
},
},
},
// =====================================================
// == LTR ==
// =====================================================
// Base
genBaseStyle(token),
// Single
genSingleStyle(token),
// Multiple
genMultipleStyle(token),
// Dropdown
genDropdownStyle(token),
// =====================================================
// == RTL ==
// =====================================================
{
[`${componentCls}-rtl`]: {
direction: 'rtl',
},
},
// =====================================================
// == Status ==
// =====================================================
genStatusStyle(
componentCls,
mergeToken<any>(token, {
borderHoverColor: token.colorPrimaryHover,
outlineColor: token.controlOutline,
}),
),
genStatusStyle(
`${componentCls}-status-error`,
mergeToken<any>(token, {
borderHoverColor: token.colorErrorHover,
outlineColor: token.colorErrorOutline,
}),
true,
),
genStatusStyle(
`${componentCls}-status-warning`,
mergeToken<any>(token, {
borderHoverColor: token.colorWarningHover,
outlineColor: token.colorWarningOutline,
}),
true,
),
// =====================================================
// == Space Compact ==
// =====================================================
genCompactItemStyle(token, {
borderElCls: `${componentCls}-selector`,
focusElCls: `${componentCls}-focused`,
}),
];
};
// ============================== Export ==============================
export default genComponentStyleHook(
'Select',
(token, { rootPrefixCls }) => {
const selectToken: SelectToken = mergeToken<SelectToken>(token, {
rootPrefixCls,
inputPaddingHorizontalBase: token.paddingSM - 1,
});
return [genSelectStyle(selectToken)];
},
token => ({
zIndexPopup: token.zIndexPopupBase + 50,
}),
);

239
components/select/style/multiple.tsx

@ -0,0 +1,239 @@
import type { CSSInterpolation, CSSObject } from '../../_util/cssinjs';
import type { SelectToken } from '.';
import { mergeToken } from '../../theme/internal';
import { resetIcon } from '../../_style';
const FIXED_ITEM_MARGIN = 2;
function getSelectItemStyle({
controlHeightSM,
controlHeight,
lineWidth: borderWidth,
}: SelectToken) {
const selectItemDist = (controlHeight - controlHeightSM) / 2 - borderWidth;
const selectItemMargin = Math.ceil(selectItemDist / 2);
return [selectItemDist, selectItemMargin];
}
function genSizeStyle(token: SelectToken, suffix?: string): CSSObject {
const { componentCls, iconCls } = token;
const selectOverflowPrefixCls = `${componentCls}-selection-overflow`;
const selectItemHeight = token.controlHeightSM;
const [selectItemDist] = getSelectItemStyle(token);
const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
return {
[`${componentCls}-multiple${suffixCls}`]: {
fontSize: token.fontSize,
/**
* Do not merge `height` & `line-height` under style with `selection` & `search`, since chrome
* may update to redesign with its align logic.
*/
// =========================== Overflow ===========================
[selectOverflowPrefixCls]: {
position: 'relative',
display: 'flex',
flex: 'auto',
flexWrap: 'wrap',
maxWidth: '100%',
'&-item': {
flex: 'none',
alignSelf: 'center',
maxWidth: '100%',
display: 'inline-flex',
},
},
// ========================= Selector =========================
[`${componentCls}-selector`]: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
// Multiple is little different that horizontal is follow the vertical
padding: `${selectItemDist - FIXED_ITEM_MARGIN}px ${FIXED_ITEM_MARGIN * 2}px`,
borderRadius: token.borderRadius,
[`${componentCls}-show-search&`]: {
cursor: 'text',
},
[`${componentCls}-disabled&`]: {
background: token.colorBgContainerDisabled,
cursor: 'not-allowed',
},
'&:after': {
display: 'inline-block',
width: 0,
margin: `${FIXED_ITEM_MARGIN}px 0`,
lineHeight: `${selectItemHeight}px`,
content: '"\\a0"',
},
},
[`
&${componentCls}-show-arrow ${componentCls}-selector,
&${componentCls}-allow-clear ${componentCls}-selector
`]: {
paddingInlineEnd: token.fontSizeIcon + token.controlPaddingHorizontal,
},
// ======================== Selections ========================
[`${componentCls}-selection-item`]: {
position: 'relative',
display: 'flex',
flex: 'none',
boxSizing: 'border-box',
maxWidth: '100%',
height: selectItemHeight,
marginTop: FIXED_ITEM_MARGIN,
marginBottom: FIXED_ITEM_MARGIN,
lineHeight: `${selectItemHeight - token.lineWidth * 2}px`,
background: token.colorFillSecondary,
border: `${token.lineWidth}px solid ${token.colorSplit}`,
borderRadius: token.borderRadiusSM,
cursor: 'default',
transition: `font-size ${token.motionDurationSlow}, line-height ${token.motionDurationSlow}, height ${token.motionDurationSlow}`,
userSelect: 'none',
marginInlineEnd: FIXED_ITEM_MARGIN * 2,
paddingInlineStart: token.paddingXS,
paddingInlineEnd: token.paddingXS / 2,
[`${componentCls}-disabled&`]: {
color: token.colorTextDisabled,
borderColor: token.colorBorder,
cursor: 'not-allowed',
},
// It's ok not to do this, but 24px makes bottom narrow in view should adjust
'&-content': {
display: 'inline-block',
marginInlineEnd: token.paddingXS / 2,
overflow: 'hidden',
whiteSpace: 'pre', // fix whitespace wrapping. custom tags display all whitespace within.
textOverflow: 'ellipsis',
},
'&-remove': {
...resetIcon(),
display: 'inline-block',
color: token.colorIcon,
fontWeight: 'bold',
fontSize: 10,
lineHeight: 'inherit',
cursor: 'pointer',
[`> ${iconCls}`]: {
verticalAlign: '-0.2em',
},
'&:hover': {
color: token.colorIconHover,
},
},
},
// ========================== Input ==========================
[`${selectOverflowPrefixCls}-item + ${selectOverflowPrefixCls}-item`]: {
[`${componentCls}-selection-search`]: {
marginInlineStart: 0,
},
},
[`${componentCls}-selection-search`]: {
display: 'inline-flex',
position: 'relative',
maxWidth: '100%',
marginInlineStart: token.inputPaddingHorizontalBase - selectItemDist,
[`
&-input,
&-mirror
`]: {
height: selectItemHeight,
fontFamily: token.fontFamily,
lineHeight: `${selectItemHeight}px`,
transition: `all ${token.motionDurationSlow}`,
},
'&-input': {
width: '100%',
minWidth: 4.1, // fix search cursor missing
},
'&-mirror': {
position: 'absolute',
top: 0,
insetInlineStart: 0,
insetInlineEnd: 'auto',
zIndex: 999,
whiteSpace: 'pre', // fix whitespace wrapping caused width calculation bug
visibility: 'hidden',
},
},
// ======================= Placeholder =======================
[`${componentCls}-selection-placeholder `]: {
position: 'absolute',
top: '50%',
insetInlineStart: token.inputPaddingHorizontalBase,
insetInlineEnd: token.inputPaddingHorizontalBase,
transform: 'translateY(-50%)',
transition: `all ${token.motionDurationSlow}`,
},
},
};
}
export default function genMultipleStyle(token: SelectToken): CSSInterpolation {
const { componentCls } = token;
const smallToken = mergeToken<SelectToken>(token, {
controlHeight: token.controlHeightSM,
controlHeightSM: token.controlHeightXS,
borderRadius: token.borderRadiusSM,
borderRadiusSM: token.borderRadiusXS,
});
const [, smSelectItemMargin] = getSelectItemStyle(token);
return [
genSizeStyle(token),
// ======================== Small ========================
// Shared
genSizeStyle(smallToken, 'sm'),
// Padding
{
[`${componentCls}-multiple${componentCls}-sm`]: {
[`${componentCls}-selection-placeholder`]: {
insetInlineStart: token.controlPaddingHorizontalSM - token.lineWidth,
insetInlineEnd: 'auto',
},
// https://github.com/ant-design/ant-design/issues/29559
[`${componentCls}-selection-search`]: {
marginInlineStart: smSelectItemMargin,
},
},
},
// ======================== Large ========================
// Shared
genSizeStyle(
mergeToken<any>(token, {
fontSize: token.fontSizeLG,
controlHeight: token.controlHeightLG,
controlHeightSM: token.controlHeight,
borderRadius: token.borderRadiusLG,
borderRadiusSM: token.borderRadius,
}),
'lg',
),
];
}

192
components/select/style/single.tsx

@ -0,0 +1,192 @@
import type { CSSInterpolation, CSSObject } from '../../_util/cssinjs';
import { resetComponent } from '../../_style';
import type { SelectToken } from '.';
import { mergeToken } from '../../theme/internal';
function genSizeStyle(token: SelectToken, suffix?: string): CSSObject {
const { componentCls, inputPaddingHorizontalBase, borderRadius } = token;
const selectHeightWithoutBorder = token.controlHeight - token.lineWidth * 2;
const selectionItemPadding = Math.ceil(token.fontSize * 1.25);
const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
return {
[`${componentCls}-single${suffixCls}`]: {
fontSize: token.fontSize,
// ========================= Selector =========================
[`${componentCls}-selector`]: {
...resetComponent(token),
display: 'flex',
borderRadius,
[`${componentCls}-selection-search`]: {
position: 'absolute',
top: 0,
insetInlineStart: inputPaddingHorizontalBase,
insetInlineEnd: inputPaddingHorizontalBase,
bottom: 0,
'&-input': {
width: '100%',
},
},
[`
${componentCls}-selection-item,
${componentCls}-selection-placeholder
`]: {
padding: 0,
lineHeight: `${selectHeightWithoutBorder}px`,
transition: `all ${token.motionDurationSlow}`,
// Firefox inline-block position calculation is not same as Chrome & Safari. Patch this:
'@supports (-moz-appearance: meterbar)': {
lineHeight: `${selectHeightWithoutBorder}px`,
},
},
[`${componentCls}-selection-item`]: {
position: 'relative',
userSelect: 'none',
},
[`${componentCls}-selection-placeholder`]: {
transition: 'none',
pointerEvents: 'none',
},
// For common baseline align
[[
'&:after',
/* For '' value baseline align */
`${componentCls}-selection-item:after`,
/* For undefined value baseline align */
`${componentCls}-selection-placeholder:after`,
].join(',')]: {
display: 'inline-block',
width: 0,
visibility: 'hidden',
content: '"\\a0"',
},
},
[`
&${componentCls}-show-arrow ${componentCls}-selection-item,
&${componentCls}-show-arrow ${componentCls}-selection-placeholder
`]: {
paddingInlineEnd: selectionItemPadding,
},
// Opacity selection if open
[`&${componentCls}-open ${componentCls}-selection-item`]: {
color: token.colorTextPlaceholder,
},
// ========================== Input ==========================
// We only change the style of non-customize input which is only support by `combobox` mode.
// Not customize
[`&:not(${componentCls}-customize-input)`]: {
[`${componentCls}-selector`]: {
width: '100%',
height: token.controlHeight,
padding: `0 ${inputPaddingHorizontalBase}px`,
[`${componentCls}-selection-search-input`]: {
height: selectHeightWithoutBorder,
},
'&:after': {
lineHeight: `${selectHeightWithoutBorder}px`,
},
},
},
[`&${componentCls}-customize-input`]: {
[`${componentCls}-selector`]: {
'&:after': {
display: 'none',
},
[`${componentCls}-selection-search`]: {
position: 'static',
width: '100%',
},
[`${componentCls}-selection-placeholder`]: {
position: 'absolute',
insetInlineStart: 0,
insetInlineEnd: 0,
padding: `0 ${inputPaddingHorizontalBase}px`,
'&:after': {
display: 'none',
},
},
},
},
},
};
}
export default function genSingleStyle(token: SelectToken): CSSInterpolation {
const { componentCls } = token;
const inputPaddingHorizontalSM = token.controlPaddingHorizontalSM - token.lineWidth;
return [
genSizeStyle(token),
// ======================== Small ========================
// Shared
genSizeStyle(
mergeToken<any>(token, {
controlHeight: token.controlHeightSM,
borderRadius: token.borderRadiusSM,
}),
'sm',
),
// padding
{
[`${componentCls}-single${componentCls}-sm`]: {
[`&:not(${componentCls}-customize-input)`]: {
[`${componentCls}-selection-search`]: {
insetInlineStart: inputPaddingHorizontalSM,
insetInlineEnd: inputPaddingHorizontalSM,
},
[`${componentCls}-selector`]: {
padding: `0 ${inputPaddingHorizontalSM}px`,
},
// With arrow should provides `padding-right` to show the arrow
[`&${componentCls}-show-arrow ${componentCls}-selection-search`]: {
insetInlineEnd: inputPaddingHorizontalSM + token.fontSize * 1.5,
},
[`
&${componentCls}-show-arrow ${componentCls}-selection-item,
&${componentCls}-show-arrow ${componentCls}-selection-placeholder
`]: {
paddingInlineEnd: token.fontSize * 1.5,
},
},
},
},
// ======================== Large ========================
// Shared
genSizeStyle(
mergeToken<any>(token, {
controlHeight: token.controlHeightLG,
fontSize: token.fontSizeLG,
borderRadius: token.borderRadiusLG,
}),
'lg',
),
];
}

2
components/style.ts

@ -23,7 +23,7 @@ import './radio/style';
// import './notification/style';
// import './message/style';
// import './spin/style';
import './select/style';
// import './select/style';
// import './switch/style';
import './auto-complete/style';
// import './affix/style';

4
components/theme/interface/components.ts

@ -31,7 +31,7 @@ import type { ComponentToken as ProgressComponentToken } from '../../progress/st
import type { ComponentToken as RateComponentToken } from '../../rate/style';
import type { ComponentToken as ResultComponentToken } from '../../result/style';
// import type { ComponentToken as SegmentedComponentToken } from '../../segmented/style';
// import type { ComponentToken as SelectComponentToken } from '../../select/style';
import type { ComponentToken as SelectComponentToken } from '../../select/style';
import type { ComponentToken as SkeletonComponentToken } from '../../skeleton/style';
import type { ComponentToken as SliderComponentToken } from '../../slider/style';
import type { ComponentToken as SpaceComponentToken } from '../../space/style';
@ -90,7 +90,7 @@ export interface ComponentTokenMap {
// Radio?: RadioComponentToken;
Result?: ResultComponentToken;
// Segmented?: SegmentedComponentToken;
// Select?: SelectComponentToken;
Select?: SelectComponentToken;
Skeleton?: SkeletonComponentToken;
Slider?: SliderComponentToken;
Spin?: SpinComponentToken;

Loading…
Cancel
Save