fix: DatePicker itemHeight calculation (#47874)

* chore: init

* chore: clean up

* chore: clean up
This commit is contained in:
二货爱吃白萝卜 2024-03-15 10:54:54 +08:00 committed by GitHub
parent 1491b0c624
commit 7884eba28e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 252 additions and 142 deletions

View File

@ -1,17 +1,13 @@
import React from 'react'; import React from 'react';
import type { DatePickerProps } from 'antd'; import { ConfigProvider, DatePicker, Divider, Flex, Space, TimePicker } from 'antd';
import { ConfigProvider, DatePicker, Space, TimePicker } from 'antd';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
/** Test usage. Do not use in your production. */ /** Test usage. Do not use in your production. */
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
const onChange: DatePickerProps['onChange'] = (date, dateString) => {
console.log(date, dateString);
};
const App: React.FC = () => ( const App: React.FC = () => (
<>
<ConfigProvider <ConfigProvider
theme={{ theme={{
components: { components: {
@ -39,13 +35,32 @@ const App: React.FC = () => (
{ label: 'Last Week', value: dayjs().add(-7, 'd') }, { label: 'Last Week', value: dayjs().add(-7, 'd') },
{ label: 'Last Month', value: dayjs().add(-1, 'month') }, { label: 'Last Month', value: dayjs().add(-1, 'month') },
]} ]}
onChange={onChange}
/> />
<RangePicker /> <RangePicker />
<TimePicker onChange={onChange} /> <TimePicker />
<DatePicker onChange={onChange} picker="month" /> <DatePicker picker="month" />
</Space> </Space>
</ConfigProvider> </ConfigProvider>
<Divider />
<ConfigProvider
theme={{
components: {
DatePicker: {
controlHeightSM: 32,
controlHeight: 40,
},
},
}}
>
<Flex vertical gap={8}>
<DatePicker multiple size="small" />
<DatePicker multiple />
<DatePicker multiple size="large" />
</Flex>
</ConfigProvider>
</>
); );
export default App; export default App;

View File

@ -1,35 +1,30 @@
import type { CSSInterpolation } from '@ant-design/cssinjs'; import type { CSSInterpolation } from '@ant-design/cssinjs';
import { unit } from '@ant-design/cssinjs';
import { FIXED_ITEM_MARGIN, genSelectionStyle } from '../../select/style/multiple'; import { genOverflowStyle, getMultipleSelectorUnit } from '../../select/style/multiple';
import { mergeToken, type GenerateStyle } from '../../theme/internal'; import { mergeToken, type GenerateStyle } from '../../theme/internal';
import type { PickerToken } from './token'; import type { PickerToken } from './token';
const genSize = (token: PickerToken, suffix?: string): CSSInterpolation => { const genSize = (token: PickerToken, suffix?: string): CSSInterpolation => {
const { componentCls, selectHeight, fontHeight, lineWidth, controlHeight, calc } = token; const { componentCls, controlHeight } = token;
const suffixCls = suffix ? `${componentCls}-${suffix}` : ''; const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
const height = token.calc(fontHeight).add(2).equal(); const multipleSelectorUnit = getMultipleSelectorUnit(token);
const restHeight = () => calc(selectHeight).sub(height).sub(calc(lineWidth).mul(2));
const paddingBase = token.max(restHeight().div(2).equal(), 0);
const paddingTop = token.max(token.calc(paddingBase).sub(FIXED_ITEM_MARGIN).equal(), 0);
const paddingBottom = token.max(
restHeight()
.sub(paddingTop)
.sub(FIXED_ITEM_MARGIN * 2)
.equal(),
0,
);
return [ return [
genSelectionStyle(token, suffix), // genSelectionStyle(token, suffix),
{ {
[`${componentCls}-multiple${suffixCls}`]: { [`${componentCls}-multiple${suffixCls}`]: {
paddingTop, paddingBlock: multipleSelectorUnit.containerPadding,
paddingBottom, paddingInlineStart: multipleSelectorUnit.basePadding,
paddingInlineStart: paddingBase,
minHeight: controlHeight, minHeight: controlHeight,
// ======================== Selections ========================
[`${componentCls}-selection-item`]: {
height: multipleSelectorUnit.itemHeight,
lineHeight: unit(multipleSelectorUnit.itemLineHeight),
},
}, },
}, },
]; ];
@ -41,7 +36,7 @@ const genPickerMultipleStyle: GenerateStyle<PickerToken> = (token) => {
const smallToken = mergeToken<PickerToken>(token, { const smallToken = mergeToken<PickerToken>(token, {
fontHeight: token.fontSize, fontHeight: token.fontSize,
selectHeight: token.controlHeightSM, selectHeight: token.controlHeightSM,
multipleSelectItemHeight: token.controlHeightXS, multipleSelectItemHeight: token.multipleItemHeightSM,
borderRadius: token.borderRadiusSM, borderRadius: token.borderRadiusSM,
borderRadiusSM: token.borderRadiusXS, borderRadiusSM: token.borderRadiusXS,
controlHeight: token.controlHeightSM, controlHeight: token.controlHeightSM,
@ -66,7 +61,6 @@ const genPickerMultipleStyle: GenerateStyle<PickerToken> = (token) => {
genSize(largeToken, 'large'), genSize(largeToken, 'large'),
// ====================== Selection ====================== // ====================== Selection ======================
genSelectionStyle(token),
{ {
[`${componentCls}${componentCls}-multiple`]: { [`${componentCls}${componentCls}-multiple`]: {
width: '100%', width: '100%',
@ -81,6 +75,9 @@ const genPickerMultipleStyle: GenerateStyle<PickerToken> = (token) => {
}, },
}, },
// ===================== Overflow ====================
...genOverflowStyle(token),
// ====================== Input ====================== // ====================== Input ======================
// Input is `readonly`, which is used for a11y only // Input is `readonly`, which is used for a11y only
[`${componentCls}-multiple-input`]: { [`${componentCls}-multiple-input`]: {

View File

@ -139,7 +139,9 @@ export const initPickerPanelToken = (token: TokenWithCommonCls<GlobalToken>): Pi
}; };
export const initPanelComponentToken = (token: GlobalToken): PanelComponentToken => { export const initPanelComponentToken = (token: GlobalToken): PanelComponentToken => {
const { colorBgContainerDisabled, controlHeightSM, controlHeightLG } = token; const { colorBgContainerDisabled, controlHeight, controlHeightSM, controlHeightLG, paddingXXS } =
token;
return { return {
cellHoverBg: token.controlItemBgHover, cellHoverBg: token.controlItemBgHover,
cellActiveWithRangeBg: token.controlItemBgActive, cellActiveWithRangeBg: token.controlItemBgActive,
@ -155,8 +157,9 @@ export const initPanelComponentToken = (token: GlobalToken): PanelComponentToken
withoutTimeCellHeight: controlHeightLG * 1.65, withoutTimeCellHeight: controlHeightLG * 1.65,
multipleItemBg: token.colorFillSecondary, multipleItemBg: token.colorFillSecondary,
multipleItemBorderColor: 'transparent', multipleItemBorderColor: 'transparent',
multipleItemHeight: controlHeightSM, multipleItemHeight: controlHeight - paddingXXS * 2,
multipleItemHeightLG: token.controlHeight, multipleItemHeightSM: controlHeightSM - paddingXXS * 2,
multipleItemHeightLG: controlHeightLG - paddingXXS * 2,
multipleSelectorBgDisabled: colorBgContainerDisabled, multipleSelectorBgDisabled: colorBgContainerDisabled,
multipleItemColorDisabled: token.colorTextDisabled, multipleItemColorDisabled: token.colorTextDisabled,
multipleItemBorderColorDisabled: 'transparent', multipleItemBorderColorDisabled: 'transparent',

View File

@ -20,6 +20,44 @@ type SelectItemToken = Pick<
| 'inputPaddingHorizontalBase' | 'inputPaddingHorizontalBase'
>; >;
/**
* Get multiple selector needed style. The calculation:
*
* ContainerPadding = BasePadding - ItemMargin
*
* Border:
* ContainerPadding:
*
* Item Margin:
*
* Item(multipleItemHeight): BasePadding Item Overflow Container(ControlHeight)
*
* Item Margin:
*
* ContainerPadding:
* Border:
*/
export const getMultipleSelectorUnit = (
token: Pick<
SelectToken,
'max' | 'calc' | 'multipleSelectItemHeight' | 'paddingXXS' | 'lineWidth'
>,
) => {
const { multipleSelectItemHeight, paddingXXS, lineWidth } = token;
const basePadding = token.max(token.calc(paddingXXS).sub(lineWidth).equal(), 0);
const containerPadding = token.max(token.calc(basePadding).sub(FIXED_ITEM_MARGIN).equal(), 0);
return {
basePadding,
containerPadding,
itemHeight: unit(multipleSelectItemHeight),
itemLineHeight: unit(
token.calc(multipleSelectItemHeight).sub(token.calc(token.lineWidth).mul(2)).equal(),
),
};
};
const getSelectItemStyle = (token: SelectItemToken): number | string => { const getSelectItemStyle = (token: SelectItemToken): number | string => {
const { multipleSelectItemHeight, selectHeight, lineWidth } = token; const { multipleSelectItemHeight, selectHeight, lineWidth } = token;
const selectItemDist = token const selectItemDist = token
@ -31,21 +69,40 @@ const getSelectItemStyle = (token: SelectItemToken): number | string => {
return selectItemDist; return selectItemDist;
}; };
export const genSelectionStyle = ( /**
token: TokenWithCommonCls<AliasToken> & SelectItemToken, * Get the `rc-overflow` needed style.
suffix?: string, * It's a share style which means not affected by `size`.
*/
export const genOverflowStyle = (
token: Pick<
SelectToken,
| 'calc'
| 'componentCls'
| 'iconCls'
| 'borderRadiusSM'
| 'motionDurationSlow'
| 'paddingXS'
| 'multipleItemColorDisabled'
| 'multipleItemBorderColorDisabled'
| 'colorIcon'
| 'colorIconHover'
>,
): CSSObject => { ): CSSObject => {
const { componentCls, iconCls } = token; const {
componentCls,
iconCls,
borderRadiusSM,
motionDurationSlow,
paddingXS,
multipleItemColorDisabled,
multipleItemBorderColorDisabled,
colorIcon,
colorIconHover,
} = token;
const selectOverflowPrefixCls = `${componentCls}-selection-overflow`; const selectOverflowPrefixCls = `${componentCls}-selection-overflow`;
const selectItemHeight = token.multipleSelectItemHeight;
const selectItemDist = getSelectItemStyle(token);
const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
return { return {
[`${componentCls}-multiple${suffixCls}`]: {
/** /**
* Do not merge `height` & `line-height` under style with `selection` & `search`, since chrome * Do not merge `height` & `line-height` under style with `selection` & `search`, since chrome
* may update to redesign with its align logic. * may update to redesign with its align logic.
@ -64,8 +121,81 @@ export const genSelectionStyle = (
maxWidth: '100%', maxWidth: '100%',
display: 'inline-flex', display: 'inline-flex',
}, },
// ======================== Selections ==========================
[`${componentCls}-selection-item`]: {
display: 'flex',
alignSelf: 'center',
flex: 'none',
boxSizing: 'border-box',
maxWidth: '100%',
marginBlock: FIXED_ITEM_MARGIN,
borderRadius: borderRadiusSM,
cursor: 'default',
transition: `font-size ${motionDurationSlow}, line-height ${motionDurationSlow}, height ${motionDurationSlow}`,
marginInlineEnd: token.calc(FIXED_ITEM_MARGIN).mul(2).equal(),
paddingInlineStart: paddingXS,
paddingInlineEnd: token.calc(paddingXS).div(2).equal(),
[`${componentCls}-disabled&`]: {
color: multipleItemColorDisabled,
borderColor: multipleItemBorderColorDisabled,
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.calc(paddingXS).div(2).equal(),
overflow: 'hidden',
whiteSpace: 'pre', // fix whitespace wrapping. custom tags display all whitespace within.
textOverflow: 'ellipsis',
},
'&-remove': {
...resetIcon(),
display: 'inline-flex',
alignItems: 'center',
color: colorIcon,
fontWeight: 'bold',
fontSize: 10,
lineHeight: 'inherit',
cursor: 'pointer',
[`> ${iconCls}`]: {
verticalAlign: '-0.2em',
},
'&:hover': {
color: colorIconHover,
},
},
},
},
};
};
const genSelectionStyle = (
token: TokenWithCommonCls<AliasToken> & SelectItemToken,
suffix?: string,
): CSSObject => {
const { componentCls } = token;
const selectOverflowPrefixCls = `${componentCls}-selection-overflow`;
const selectItemHeight = token.multipleSelectItemHeight;
const selectItemDist = getSelectItemStyle(token);
const suffixCls = suffix ? `${componentCls}-${suffix}` : '';
const multipleSelectorUnit = getMultipleSelectorUnit(token);
return {
[`${componentCls}-multiple${suffixCls}`]: {
// ========================= Overflow =========================
...genOverflowStyle(token),
// ========================= Selector ========================= // ========================= Selector =========================
[`${componentCls}-selector`]: { [`${componentCls}-selector`]: {
display: 'flex', display: 'flex',
@ -73,8 +203,8 @@ export const genSelectionStyle = (
alignItems: 'center', alignItems: 'center',
height: '100%', height: '100%',
// Multiple is little different that horizontal is follow the vertical // Multiple is little different that horizontal is follow the vertical
paddingInline: token.calc(FIXED_ITEM_MARGIN).mul(2).equal(), paddingInline: multipleSelectorUnit.basePadding,
paddingBlock: token.calc(selectItemDist).sub(FIXED_ITEM_MARGIN).equal(), paddingBlock: multipleSelectorUnit.containerPadding,
borderRadius: token.borderRadius, borderRadius: token.borderRadius,
[`${componentCls}-disabled&`]: { [`${componentCls}-disabled&`]: {
@ -94,58 +224,8 @@ export const genSelectionStyle = (
// ======================== Selections ======================== // ======================== Selections ========================
[`${componentCls}-selection-item`]: { [`${componentCls}-selection-item`]: {
display: 'flex', height: multipleSelectorUnit.itemHeight,
alignSelf: 'center', lineHeight: unit(multipleSelectorUnit.itemLineHeight),
flex: 'none',
boxSizing: 'border-box',
maxWidth: '100%',
height: selectItemHeight,
marginTop: FIXED_ITEM_MARGIN,
marginBottom: FIXED_ITEM_MARGIN,
lineHeight: unit(
token.calc(selectItemHeight).sub(token.calc(token.lineWidth).mul(2)).equal(),
),
borderRadius: token.borderRadiusSM,
cursor: 'default',
transition: `font-size ${token.motionDurationSlow}, line-height ${token.motionDurationSlow}, height ${token.motionDurationSlow}`,
marginInlineEnd: token.calc(FIXED_ITEM_MARGIN).mul(2).equal(),
paddingInlineStart: token.paddingXS,
paddingInlineEnd: token.calc(token.paddingXS).div(2).equal(),
[`${componentCls}-disabled&`]: {
color: token.multipleItemColorDisabled,
borderColor: token.multipleItemBorderColorDisabled,
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.calc(token.paddingXS).div(2).equal(),
overflow: 'hidden',
whiteSpace: 'pre', // fix whitespace wrapping. custom tags display all whitespace within.
textOverflow: 'ellipsis',
},
'&-remove': {
...resetIcon(),
display: 'inline-flex',
alignItems: 'center',
color: token.colorIcon,
fontWeight: 'bold',
fontSize: 10,
lineHeight: 'inherit',
cursor: 'pointer',
[`> ${iconCls}`]: {
verticalAlign: '-0.2em',
},
'&:hover': {
color: token.colorIconHover,
},
},
}, },
// ========================== Input ========================== // ========================== Input ==========================
@ -241,7 +321,7 @@ const genMultipleStyle = (token: SelectToken): CSSInterpolation => {
const smallToken = mergeToken<SelectToken>(token, { const smallToken = mergeToken<SelectToken>(token, {
selectHeight: token.controlHeightSM, selectHeight: token.controlHeightSM,
multipleSelectItemHeight: token.controlHeightXS, multipleSelectItemHeight: token.multipleItemHeightSM,
borderRadius: token.borderRadiusSM, borderRadius: token.borderRadiusSM,
borderRadiusSM: token.borderRadiusXS, borderRadiusSM: token.borderRadiusXS,
}); });

View File

@ -17,6 +17,11 @@ export interface MultipleSelectorToken {
* @descEN Height of multiple tag * @descEN Height of multiple tag
*/ */
multipleItemHeight: number; multipleItemHeight: number;
/**
* @desc
* @descEN Height of multiple tag with small size
*/
multipleItemHeightSM: number;
/** /**
* @desc * @desc
* @descEN Height of multiple tag with large size * @descEN Height of multiple tag with large size
@ -121,7 +126,13 @@ export const prepareComponentToken: GetDefaultToken<'Select'> = (token) => {
const { const {
fontSize, fontSize,
lineHeight, lineHeight,
controlHeight, controlHeight,
controlHeightSM,
controlHeightLG,
paddingXXS,
controlPaddingHorizontal, controlPaddingHorizontal,
zIndexPopupBase, zIndexPopupBase,
colorText, colorText,
@ -130,12 +141,15 @@ export const prepareComponentToken: GetDefaultToken<'Select'> = (token) => {
controlItemBgHover, controlItemBgHover,
colorBgContainer, colorBgContainer,
colorFillSecondary, colorFillSecondary,
controlHeightLG,
controlHeightSM,
colorBgContainerDisabled, colorBgContainerDisabled,
colorTextDisabled, colorTextDisabled,
} = token; } = token;
const multipleItemHeight = controlHeight - paddingXXS * 2;
const multipleItemHeightSM = controlHeightSM - paddingXXS * 2;
const multipleItemHeightLG = controlHeightLG - paddingXXS * 2;
return { return {
zIndexPopup: zIndexPopupBase + 50, zIndexPopup: zIndexPopupBase + 50,
optionSelectedColor: colorText, optionSelectedColor: colorText,
@ -151,8 +165,9 @@ export const prepareComponentToken: GetDefaultToken<'Select'> = (token) => {
singleItemHeightLG: controlHeightLG, singleItemHeightLG: controlHeightLG,
multipleItemBg: colorFillSecondary, multipleItemBg: colorFillSecondary,
multipleItemBorderColor: 'transparent', multipleItemBorderColor: 'transparent',
multipleItemHeight: controlHeightSM, multipleItemHeight,
multipleItemHeightLG: controlHeight, multipleItemHeightSM,
multipleItemHeightLG,
multipleSelectorBgDisabled: colorBgContainerDisabled, multipleSelectorBgDisabled: colorBgContainerDisabled,
multipleItemColorDisabled: colorTextDisabled, multipleItemColorDisabled: colorTextDisabled,
multipleItemBorderColorDisabled: 'transparent', multipleItemBorderColorDisabled: 'transparent',