From 5137d0f56fd8593f4bb7797fb382417865abc1d1 Mon Sep 17 00:00:00 2001 From: songsichen Date: Mon, 28 Apr 2025 11:19:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20QIANXING1-787=20Menu=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81CSS=20Var?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/menu/src/Menu.tsx | 8 +- components/menu/src/SubMenu.tsx | 2 + components/menu/src/hooks/useMenuContext.ts | 1 + components/menu/style/horizontal.ts | 11 +- components/menu/style/index.ts | 867 ++++++++++++++++---- components/menu/style/rtl.ts | 13 +- components/menu/style/theme.ts | 171 ++-- components/menu/style/vertical.ts | 61 +- 8 files changed, 850 insertions(+), 284 deletions(-) diff --git a/components/menu/src/Menu.tsx b/components/menu/src/Menu.tsx index bd8addbfa1..de9609eefd 100644 --- a/components/menu/src/Menu.tsx +++ b/components/menu/src/Menu.tsx @@ -43,6 +43,7 @@ import type { ItemType } from './hooks/useItems'; import useItems from './hooks/useItems'; import useStyle from '../style'; import { useInjectOverride } from './OverrideContext'; +import useCSSVarCls from '../../config-provider/hooks/useCssVarCls'; export const menuProps = () => ({ id: String, @@ -106,8 +107,10 @@ export default defineComponent({ const prefixCls = computed(() => { return getPrefixCls('menu', props.prefixCls || override?.prefixCls?.value); }); - const [wrapSSR, hashId] = useStyle( + const rootCls = useCSSVarCls(prefixCls); + const [wrapSSR, hashId, cssVarCls] = useStyle( prefixCls, + rootCls, computed(() => { return !override; }), @@ -336,6 +339,8 @@ export default defineComponent({ [`${prefixCls.value}-inline-collapsed`]: mergedInlineCollapsed.value, [`${prefixCls.value}-rtl`]: isRtl.value, [`${prefixCls.value}-${props.theme}`]: true, + [rootCls.value]: true, + [cssVarCls.value]: true, }; }); const rootPrefixCls = computed(() => getPrefixCls()); @@ -411,6 +416,7 @@ export default defineComponent({ ); useProvideMenu({ prefixCls, + cssVarCls: computed(() => `${rootCls.value} ${cssVarCls.value}`), activeKeys, openKeys: mergedOpenKeys, selectedKeys: mergedSelectedKeys, diff --git a/components/menu/src/SubMenu.tsx b/components/menu/src/SubMenu.tsx index b95076e651..01d8e53441 100644 --- a/components/menu/src/SubMenu.tsx +++ b/components/menu/src/SubMenu.tsx @@ -103,6 +103,7 @@ export default defineComponent({ const { prefixCls, + cssVarCls, activeKeys, disabled: contextDisabled, changeActiveKeys, @@ -210,6 +211,7 @@ export default defineComponent({ const popupClassName = computed(() => classNames( + cssVarCls.value, prefixCls.value, `${prefixCls.value}-${props.theme || theme.value}`, props.popupClassName, diff --git a/components/menu/src/hooks/useMenuContext.ts b/components/menu/src/hooks/useMenuContext.ts index d6ff2b9c52..6498a34f72 100644 --- a/components/menu/src/hooks/useMenuContext.ts +++ b/components/menu/src/hooks/useMenuContext.ts @@ -23,6 +23,7 @@ export interface MenuContextProps { registerMenuInfo: (key: string, info: StoreMenuInfo) => void; unRegisterMenuInfo: (key: string) => void; prefixCls: ComputedRef; + cssVarCls: ComputedRef; openKeys: Ref; selectedKeys: Ref; diff --git a/components/menu/style/horizontal.ts b/components/menu/style/horizontal.ts index 31bec2c1ff..a2a46e9ae4 100644 --- a/components/menu/style/horizontal.ts +++ b/components/menu/style/horizontal.ts @@ -1,3 +1,4 @@ +import { unit } from '../../_util/cssinjs'; import type { MenuToken } from '.'; import type { GenerateStyle } from '../../theme/internal'; @@ -5,18 +6,18 @@ const getHorizontalStyle: GenerateStyle = token => { const { componentCls, motionDurationSlow, - menuHorizontalHeight, + horizontalLineHeight, colorSplit, lineWidth, lineType, - menuItemPaddingInline, + itemPaddingInline, } = token; return { [`${componentCls}-horizontal`]: { - lineHeight: `${menuHorizontalHeight}px`, + lineHeight: horizontalLineHeight, border: 0, - borderBottom: `${lineWidth}px ${lineType} ${colorSplit}`, + borderBottom: `${unit(lineWidth)} ${lineType} ${colorSplit}`, boxShadow: 'none', '&::after': { @@ -31,7 +32,7 @@ const getHorizontalStyle: GenerateStyle = token => { position: 'relative', display: 'inline-block', verticalAlign: 'bottom', - paddingInline: menuItemPaddingInline, + paddingInline: itemPaddingInline, }, [`> ${componentCls}-item:hover, diff --git a/components/menu/style/index.ts b/components/menu/style/index.ts index 89661da305..e46bcd56ba 100644 --- a/components/menu/style/index.ts +++ b/components/menu/style/index.ts @@ -1,83 +1,420 @@ +import type { CSSProperties, Ref } from 'vue'; import { TinyColor } from '@ctrl/tinycolor'; -import type { CSSObject } from '../../_util/cssinjs'; + +import type { CSSUtil } from '../../theme/util/genComponentStyleHook'; +import { unit, CSSObject } from '../../_util/cssinjs'; +import { clearFix, resetComponent, resetIcon } from '../../style'; import { genCollapseMotion, initSlideMotion, initZoomMotion } from '../../style/motion'; -import type { FullToken, GenerateStyle, UseComponentStyleResult } from '../../theme/internal'; -import { genComponentStyleHook, mergeToken } from '../../theme/internal'; +import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal'; +import { genStyleHooks, mergeToken } from '../../theme/internal'; import getHorizontalStyle from './horizontal'; import getRTLStyle from './rtl'; import getThemeStyle from './theme'; import getVerticalStyle from './vertical'; -import { clearFix, resetComponent, resetIcon } from '../../style'; -import { Ref } from 'vue'; /** Component only token. Which will handle additional calculation of alias token */ export interface ComponentToken { - dropdownWidth: number; + /** + * @desc 弹出菜单的宽度 + * @descEN Width of popup menu + */ + dropdownWidth: number | string; + /** + * @desc 弹出菜单的 z-index + * @descEN z-index of popup menu + */ zIndexPopup: number; // Group + /** @deprecated Use `groupTitleColor` instead */ colorGroupTitle: string; + /** + * @desc 分组标题文字颜色 + * @descEN Color of group title text + */ + groupTitleColor: string; + /** + * @desc 分组标题文字高度 + * @descEN line-height of group title + */ + groupTitleLineHeight: string | number; + /** + * @desc 分组标题文字大小 + * @descEN font-size of group title + */ + groupTitleFontSize: number; // radius + /** @deprecated Use `itemBorderRadius` instead */ radiusItem: number; + /** + * @desc 菜单项的圆角 + * @descEN Radius of menu item + */ + itemBorderRadius: number; + + /** @deprecated Use `subMenuItemBorderRadius` instead */ radiusSubMenuItem: number; + /** + * @desc 子菜单项的圆角 + * @descEN Radius of sub-menu item + */ + subMenuItemBorderRadius: number; // Item Text // > Default + /** @deprecated Use `itemColor` instead */ colorItemText: string; + /** + * @desc 菜单项文字颜色 + * @descEN Color of menu item text + */ + itemColor: string; + + /** @deprecated Use `itemHoverColor` instead */ colorItemTextHover: string; + /** + * @desc 菜单项文字悬浮颜色 + * @descEN Hover color of menu item text + */ + itemHoverColor: string; + + /** @deprecated Use `horizontalItemHoverColor` instead */ colorItemTextHoverHorizontal: string; + /** + * @desc 水平菜单项文字悬浮颜色 + * @descEN Hover color of horizontal menu item text + */ + horizontalItemHoverColor: string; + + /** @deprecated Use `itemSelectedColor` instead */ colorItemTextSelected: string; + /** + * @desc 菜单项文字选中颜色 + * @descEN Color of selected menu item text + */ + itemSelectedColor: string; + /** + * @desc 子菜单内有选中项时,子菜单标题色 + * @descEN Color of submenu title when submenu has selected item + */ + subMenuItemSelectedColor: string; + + /** @deprecated Use `horizontalItemSelectedColor` instead */ colorItemTextSelectedHorizontal: string; + /** + * @desc 水平菜单项文字选中颜色 + * @descEN Color of selected horizontal menu item text + */ + horizontalItemSelectedColor: string; // > Disabled + /** @deprecated Use `itemDisabledColor` instead */ colorItemTextDisabled: string; + /** + * @desc 菜单项文字禁用颜色 + * @descEN Color of disabled menu item text + */ + itemDisabledColor: string; // > Danger + /** @deprecated Use `dangerItemColor` instead */ colorDangerItemText: string; + /** + * @desc 危险菜单项文字颜色 + * @descEN Color of danger menu item text + */ + dangerItemColor: string; + + /** @deprecated Use `dangerItemHoverColor` instead */ colorDangerItemTextHover: string; + /** + * @desc 危险菜单项文字悬浮颜色 + * @descEN Hover color of danger menu item text + */ + dangerItemHoverColor: string; + + /** @deprecated Use `dangerItemSelectedColor` instead */ colorDangerItemTextSelected: string; + /** + * @desc 危险菜单项文字选中颜色 + * @descEN Color of selected danger menu item text + */ + dangerItemSelectedColor: string; + + /** @deprecated Use `dangerItemActiveBg` instead */ colorDangerItemBgActive: string; + /** + * @desc 危险菜单项激活态背景色 + * @descEN Background color of danger menu item when active + */ + dangerItemActiveBg: string; + + /** @deprecated Use `dangerItemSelectedBg` instead */ colorDangerItemBgSelected: string; + /** + * @desc 危险菜单项选中背景色 + * @descEN Background color of selected danger menu item + */ + dangerItemSelectedBg: string; // Item Bg + /** @deprecated Use `itemBg` instead */ colorItemBg: string; + /** + * @desc 菜单项背景色 + */ + itemBg: string; + + /** @deprecated Use `itemHoverBg` instead */ colorItemBgHover: string; + /** + * @desc 菜单项悬浮态背景色 + * @descEN Background color of menu item when hover + */ + itemHoverBg: string; + + /** @deprecated Use `subMenuItemBg` instead */ colorSubItemBg: string; + /** + * @desc 子菜单项背景色 + * @descEN Background color of sub-menu item + */ + subMenuItemBg: string; // > Default + /** @deprecated Use `itemActiveBg` instead */ colorItemBgActive: string; + /** + * @desc 菜单项激活态背景色 + * @descEN Background color of menu item when active + */ + itemActiveBg: string; + + /** @deprecated Use `itemSelectedBg` instead */ colorItemBgSelected: string; + /** + * @desc 菜单项选中态背景色 + * @descEN Background color of menu item when selected + */ + itemSelectedBg: string; + + /** @deprecated Use `horizontalItemSelectedBg` instead */ colorItemBgSelectedHorizontal: string; + /** + * @desc 水平菜单项选中态背景色 + * @descEN Background color of horizontal menu item when selected + */ + horizontalItemSelectedBg: string; // Ink Bar - colorActiveBarWidth: number; + /** @deprecated Use `activeBarWidth` instead */ + colorActiveBarWidth: number | string; + /** + * @desc 菜单项指示条宽度 + * @descEN Width of menu item active bar + */ + activeBarWidth: number | string; + + /** @deprecated Use `activeBarHeight` instead */ colorActiveBarHeight: number; - colorActiveBarBorderSize: number; + /** + * @desc 菜单项指示条高度 + * @descEN Height of menu item active bar + */ + activeBarHeight: number; + /** @deprecated Use `activeBarBorderWidth` instead */ + colorActiveBarBorderSize: number; + /** + * @desc 菜单项指示条边框宽度 + * @descEN Border width of menu item active bar + */ + activeBarBorderWidth: number | string; + + /** + * @desc 菜单项横向外间距 + * @descEN Horizontal margin of menu item + */ itemMarginInline: number; + /** + * @desc 横向菜单项横悬浮态背景色 + * @descEN Background color of horizontal menu item when hover + */ + horizontalItemHoverBg: string; + /** + * @desc 横向菜单项圆角 + * @descEN Border radius of horizontal menu item + */ + horizontalItemBorderRadius: number; + /** + * @desc 菜单项高度 + * @descEN Height of menu item + */ + itemHeight: number | string; + /** + * @desc 收起后的宽度 + * @descEN Width when collapsed + */ + collapsedWidth: number | string; + /** + * @desc 弹出框背景色 + * @descEN Background color of popup + */ + popupBg: string; + /** + * @desc 菜单项纵向外间距 + * @descEN margin-block of menu item + */ + itemMarginBlock: CSSProperties['marginBlock']; + /** + * @desc 菜单项横向内间距 + * @descEN padding-inline of menu item + */ + itemPaddingInline: CSSProperties['paddingInline']; + /** + * @desc 横向菜单行高 + * @descEN LineHeight of horizontal menu item + */ + horizontalLineHeight: CSSProperties['lineHeight']; + /** + * @desc 图标与文字间距 + * @descEN Spacing between icon and text + */ + iconMarginInlineEnd: CSSProperties['marginInlineEnd']; + /** + * @desc 图标尺寸 + * @descEN Size of icon + */ + iconSize: number; + /** + * @desc 收起时图标尺寸 + * @descEN Size of icon when collapsed + */ + collapsedIconSize: number; + + // Dark + /** + * @desc 暗色模式下的浮层菜单的背景颜色 + * @descEN The background color of the overlay menu in dark mode. + */ + darkPopupBg: string; + /** + * @desc 暗色模式下的菜单项文字颜色 + * @descEN Color of menu item text in dark mode + */ + darkItemColor: string; + /** + * @desc 暗色模式下的危险菜单项文字颜色 + * @descEN Color of danger menu item text in dark mode + */ + darkDangerItemColor: string; + /** + * @desc 暗色模式下的菜单项背景 + * @descEN Background of menu item in dark mode + */ + darkItemBg: string; + /** + * @desc 暗色模式下的子菜单项背景 + * @descEN Background of submenu item in dark mode + */ + darkSubMenuItemBg: string; + /** + * @desc 暗色模式下的菜单项选中颜色 + * @descEN Color of selected menu item in dark mode + */ + darkItemSelectedColor: string; + /** + * @desc 暗色模式下的菜单项选中背景 + * @descEN Background of active menu item in dark mode + */ + darkItemSelectedBg: string; + /** + * @desc 暗色模式下的菜单项悬浮背景 + * @descEN Background of hovered menu item in dark mode + */ + darkItemHoverBg: string; + /** + * @desc 暗色模式下的分组标题文字颜色 + * @descEN Color of group title text in dark mode + */ + darkGroupTitleColor: string; + /** + * @desc 暗色模式下的菜单项悬浮颜色 + * @descEN Color of hovered menu item in dark mode + */ + darkItemHoverColor: string; + /** + * @desc 暗色模式下的菜单项禁用颜色 + * @descEN Color of disabled menu item in dark mode + */ + darkItemDisabledColor: string; + /** + * @desc 暗色模式下的危险菜单项选中背景 + * @descEN Background of active danger menu item in dark mode + */ + darkDangerItemSelectedBg: string; + /** + * @desc 暗色模式下的危险菜单项悬浮文字背景 + * @descEN Background of hovered danger menu item in dark mode + */ + darkDangerItemHoverColor: string; + /** + * @desc 暗色模式下的危险菜单项选中文字颜色 + * @descEN Color of selected danger menu item in dark mode + */ + darkDangerItemSelectedColor: string; + /** + * @desc 暗色模式下的危险菜单项激活态背景 + * @descEN Background of active danger menu item in dark mode + */ + darkDangerItemActiveBg: string; + /** @internal */ + itemWidth: number | string; } +/** + * @desc Menu 组件的 Token + * @descEN Token for Menu component + */ export interface MenuToken extends FullToken<'Menu'> { - menuItemHeight: number; - menuHorizontalHeight: number; - menuItemPaddingInline: number; - menuArrowSize: number; - menuArrowOffset: string; - menuPanelMaskInset: number; + /** + * @desc 水平菜单高度 + * @descEN Height of horizontal menu + */ + menuHorizontalHeight: number | string; + /** + * @desc 菜单箭头尺寸 + * @descEN Size of menu arrow + */ + menuArrowSize: number | string; + /** + * @desc 菜单箭头偏移量 + * @descEN Offset of menu arrow + */ + menuArrowOffset: number | string; + /** + * @desc 子菜单背景色 + * @descEN Background color of sub-menu + */ menuSubMenuBg: string; + /** + * @desc 暗色模式下的浮层菜单背景色 + * @descEN Background color of popup menu in dark mode + */ + darkPopupBg: string; } const genMenuItemStyle = (token: MenuToken): CSSObject => { const { componentCls, - fontSize, motionDurationSlow, motionDurationMid, motionEaseInOut, motionEaseOut, iconCls, - controlHeightSM, + iconSize, + iconMarginInlineEnd, } = token; return { @@ -91,12 +428,12 @@ const genMenuItemStyle = (token: MenuToken): CSSObject => { transition: [ `border-color ${motionDurationSlow}`, `background ${motionDurationSlow}`, - `padding ${motionDurationSlow} ${motionEaseInOut}`, + `padding calc(${motionDurationSlow} + 0.1s) ${motionEaseInOut}`, ].join(','), [`${componentCls}-item-icon, ${iconCls}`]: { - minWidth: fontSize, - fontSize, + minWidth: iconSize, + fontSize: iconSize, transition: [ `font-size ${motionDurationMid} ${motionEaseOut}`, `margin ${motionDurationSlow} ${motionEaseInOut}`, @@ -104,7 +441,7 @@ const genMenuItemStyle = (token: MenuToken): CSSObject => { ].join(','), '+ span': { - marginInlineStart: controlHeightSM - fontSize, + marginInlineStart: iconMarginInlineEnd, opacity: 1, transition: [ `opacity ${motionDurationSlow} ${motionEaseInOut}`, @@ -136,6 +473,8 @@ const genMenuItemStyle = (token: MenuToken): CSSObject => { a: { color: 'inherit !important', + cursor: 'not-allowed', + pointerEvents: 'none', }, [`> ${componentCls}-submenu-title`]: { @@ -158,7 +497,7 @@ const genSubMenuArrowStyle = (token: MenuToken): CSSObject => { return { [`${componentCls}-submenu`]: { - [`&-expand-icon, &-arrow`]: { + '&-expand-icon, &-arrow': { position: 'absolute', top: '50%', insetInlineEnd: token.margin, @@ -172,8 +511,8 @@ const genSubMenuArrowStyle = (token: MenuToken): CSSObject => { // → '&::before, &::after': { position: 'absolute', - width: menuArrowSize * 0.6, - height: menuArrowSize * 0.15, + width: token.calc(menuArrowSize).mul(0.6).equal(), + height: token.calc(menuArrowSize).mul(0.15).equal(), backgroundColor: 'currentcolor', borderRadius, transition: [ @@ -186,11 +525,13 @@ const genSubMenuArrowStyle = (token: MenuToken): CSSObject => { }, '&::before': { - transform: `rotate(45deg) translateY(-${menuArrowOffset})`, + transform: `rotate(45deg) translateY(${unit( + token.calc(menuArrowOffset).mul(-1).equal(), + )})`, }, '&::after': { - transform: `rotate(-45deg) translateY(${menuArrowOffset})`, + transform: `rotate(-45deg) translateY(${unit(menuArrowOffset)})`, }, }, }, @@ -206,29 +547,29 @@ const getBaseStyle: GenerateStyle = token => { motionDurationSlow, motionDurationMid, motionEaseInOut, - lineHeight, paddingXS, padding, colorSplit, lineWidth, zIndexPopup, borderRadiusLG, - radiusSubMenuItem, + subMenuItemBorderRadius, menuArrowSize, menuArrowOffset, lineType, - menuPanelMaskInset, + groupTitleLineHeight, + groupTitleFontSize, } = token; return [ // Misc { '': { - [`${componentCls}`]: { + [componentCls]: { ...clearFix(), // Hidden - [`&-hidden`]: { + '&-hidden': { display: 'none', }, }, @@ -248,16 +589,17 @@ const getBaseStyle: GenerateStyle = token => { lineHeight: 0, // Fix display inline-block gap listStyle: 'none', outline: 'none', + // Magic cubic here but smooth transition transition: `width ${motionDurationSlow} cubic-bezier(0.2, 0, 0, 1) 0s`, - [`ul, ol`]: { + 'ul, ol': { margin: 0, padding: 0, listStyle: 'none', }, // Overflow ellipsis - [`&-overflow`]: { + '&-overflow': { display: 'flex', [`${componentCls}-item`]: { @@ -265,13 +607,13 @@ const getBaseStyle: GenerateStyle = token => { }, }, [`${componentCls}-item, ${componentCls}-submenu, ${componentCls}-submenu-title`]: { - borderRadius: token.radiusItem, + borderRadius: token.itemBorderRadius, }, [`${componentCls}-item-group-title`]: { - padding: `${paddingXS}px ${padding}px`, - fontSize, - lineHeight, + padding: `${unit(paddingXS)} ${unit(padding)}`, + fontSize: groupTitleFontSize, + lineHeight: groupTitleLineHeight, transition: `all ${motionDurationSlow}`, }, @@ -300,6 +642,23 @@ const getBaseStyle: GenerateStyle = token => { [`${componentCls}-title-content`]: { transition: `color ${motionDurationSlow}`, + + '&-with-extra': { + display: 'inline-flex', + alignItems: 'center', + width: '100%', + }, + + // https://github.com/ant-design/ant-design/issues/41143 + [`> ${antCls}-typography-ellipsis-single-line`]: { + display: 'inline', + verticalAlign: 'unset', + }, + + [`${componentCls}-item-extra`]: { + marginInlineStart: 'auto', + paddingInlineStart: token.padding, + }, }, [`${componentCls}-item a`]: { @@ -339,7 +698,7 @@ const getBaseStyle: GenerateStyle = token => { padding: 0, [`${componentCls}-item, ${componentCls}-submenu-title`]: { - paddingInline: `${fontSize * 2}px ${padding}px`, + paddingInline: `${unit(token.calc(fontSize).mul(2).equal())} ${unit(padding)}`, }, }, }, @@ -349,42 +708,95 @@ const getBaseStyle: GenerateStyle = token => { '&-popup': { position: 'absolute', zIndex: zIndexPopup, - background: 'transparent', borderRadius: borderRadiusLG, boxShadow: 'none', transformOrigin: '0 0', + [`&${componentCls}-submenu`]: { + background: 'transparent', + }, + // https://github.com/ant-design/ant-design/issues/13955 '&::before': { position: 'absolute', - inset: `${menuPanelMaskInset}px 0 0`, + inset: 0, zIndex: -1, width: '100%', height: '100%', opacity: 0, content: '""', }, + + [`> ${componentCls}`]: { + borderRadius: borderRadiusLG, + + ...genMenuItemStyle(token), + ...genSubMenuArrowStyle(token), + + [`${componentCls}-item, ${componentCls}-submenu > ${componentCls}-submenu-title`]: { + borderRadius: subMenuItemBorderRadius, + }, + + [`${componentCls}-submenu-title::after`]: { + transition: `transform ${motionDurationSlow} ${motionEaseInOut}`, + }, + }, }, - // https://github.com/ant-design/ant-design/issues/13955 - '&-placement-rightTop::before': { - top: 0, - insetInlineStart: menuPanelMaskInset, + [` + &-placement-leftTop, + &-placement-bottomRight, + `]: { + transformOrigin: '100% 0', }, - [`> ${componentCls}`]: { - borderRadius: borderRadiusLG, + [` + &-placement-leftBottom, + &-placement-topRight, + `]: { + transformOrigin: '100% 100%', + }, - ...genMenuItemStyle(token), - ...genSubMenuArrowStyle(token), + [` + &-placement-rightBottom, + &-placement-topLeft, + `]: { + transformOrigin: '0 100%', + }, - [`${componentCls}-item, ${componentCls}-submenu > ${componentCls}-submenu-title`]: { - borderRadius: radiusSubMenuItem, - }, + [` + &-placement-bottomLeft, + &-placement-rightTop, + `]: { + transformOrigin: '0 0', + }, - [`${componentCls}-submenu-title::after`]: { - transition: `transform ${motionDurationSlow} ${motionEaseInOut}`, - }, + [` + &-placement-leftTop, + &-placement-leftBottom + `]: { + paddingInlineEnd: token.paddingXS, + }, + + [` + &-placement-rightTop, + &-placement-rightBottom + `]: { + paddingInlineStart: token.paddingXS, + }, + + [` + &-placement-topRight, + &-placement-topLeft + `]: { + paddingBottom: token.paddingXS, + }, + + [` + &-placement-bottomRight, + &-placement-bottomLeft + `]: { + paddingTop: token.paddingXS, }, }, @@ -394,25 +806,29 @@ const getBaseStyle: GenerateStyle = token => { &-inline ${componentCls}-submenu-arrow`]: { // ↓ '&::before': { - transform: `rotate(-45deg) translateX(${menuArrowOffset})`, + transform: `rotate(-45deg) translateX(${unit(menuArrowOffset)})`, }, '&::after': { - transform: `rotate(45deg) translateX(-${menuArrowOffset})`, + transform: `rotate(45deg) translateX(${unit( + token.calc(menuArrowOffset).mul(-1).equal(), + )})`, }, }, [`${componentCls}-submenu-open${componentCls}-submenu-inline > ${componentCls}-submenu-title > ${componentCls}-submenu-arrow`]: { // ↑ - transform: `translateY(-${menuArrowSize * 0.2}px)`, + transform: `translateY(${unit(token.calc(menuArrowSize).mul(0.2).mul(-1).equal())})`, '&::after': { - transform: `rotate(-45deg) translateX(-${menuArrowOffset})`, + transform: `rotate(-45deg) translateX(${unit( + token.calc(menuArrowOffset).mul(-1).equal(), + )})`, }, '&::before': { - transform: `rotate(45deg) translateX(${menuArrowOffset})`, + transform: `rotate(45deg) translateX(${unit(menuArrowOffset)})`, }, }, }, @@ -429,71 +845,210 @@ const getBaseStyle: GenerateStyle = token => { ]; }; -// ============================== Export ============================== -export default (prefixCls: Ref, injectStyle?: Ref): UseComponentStyleResult => { - const useOriginHook = genComponentStyleHook( - 'Menu', - (token, { overrideComponentToken }) => { - // Dropdown will handle menu style self. We do not need to handle this. - if (injectStyle?.value === false) { - return []; - } +export const prepareComponentToken: GetDefaultToken<'Menu'> = token => { + const { + colorPrimary, + colorError, + colorTextDisabled, + colorErrorBg, + colorText, + colorTextDescription, + colorBgContainer, + colorFillAlter, + colorFillContent, + lineWidth, + lineWidthBold, + controlItemBgActive, + colorBgTextHover, + controlHeightLG, + lineHeight, + colorBgElevated, + marginXXS, + padding, + fontSize, + controlHeightSM, + fontSizeLG, + colorTextLightSolid, + colorErrorHover, + } = token; + + const activeBarWidth = token.activeBarWidth ?? 0; + const activeBarBorderWidth = token.activeBarBorderWidth ?? lineWidth; + const itemMarginInline = token.itemMarginInline ?? token.marginXXS; - const { colorBgElevated, colorPrimary, colorError, colorErrorHover, colorTextLightSolid } = - token; + const colorTextDark = new TinyColor(colorTextLightSolid).setAlpha(0.65).toRgbString(); - const { controlHeightLG, fontSize } = token; + return { + dropdownWidth: 160, + zIndexPopup: token.zIndexPopupBase + 50, + radiusItem: token.borderRadiusLG, + itemBorderRadius: token.borderRadiusLG, + radiusSubMenuItem: token.borderRadiusSM, + subMenuItemBorderRadius: token.borderRadiusSM, + colorItemText: colorText, + itemColor: colorText, + colorItemTextHover: colorText, + itemHoverColor: colorText, + colorItemTextHoverHorizontal: colorPrimary, + horizontalItemHoverColor: colorPrimary, + colorGroupTitle: colorTextDescription, + groupTitleColor: colorTextDescription, + colorItemTextSelected: colorPrimary, + itemSelectedColor: colorPrimary, + subMenuItemSelectedColor: colorPrimary, + colorItemTextSelectedHorizontal: colorPrimary, + horizontalItemSelectedColor: colorPrimary, + colorItemBg: colorBgContainer, + itemBg: colorBgContainer, + colorItemBgHover: colorBgTextHover, + itemHoverBg: colorBgTextHover, + colorItemBgActive: colorFillContent, + itemActiveBg: controlItemBgActive, + colorSubItemBg: colorFillAlter, + subMenuItemBg: colorFillAlter, + colorItemBgSelected: controlItemBgActive, + itemSelectedBg: controlItemBgActive, + colorItemBgSelectedHorizontal: 'transparent', + horizontalItemSelectedBg: 'transparent', + colorActiveBarWidth: 0, + activeBarWidth, + colorActiveBarHeight: lineWidthBold, + activeBarHeight: lineWidthBold, + colorActiveBarBorderSize: lineWidth, + activeBarBorderWidth, + + // Disabled + colorItemTextDisabled: colorTextDisabled, + itemDisabledColor: colorTextDisabled, + + // Danger + colorDangerItemText: colorError, + dangerItemColor: colorError, + colorDangerItemTextHover: colorError, + dangerItemHoverColor: colorError, + colorDangerItemTextSelected: colorError, + dangerItemSelectedColor: colorError, + colorDangerItemBgActive: colorErrorBg, + dangerItemActiveBg: colorErrorBg, + colorDangerItemBgSelected: colorErrorBg, + dangerItemSelectedBg: colorErrorBg, + + itemMarginInline, + + horizontalItemBorderRadius: 0, + horizontalItemHoverBg: 'transparent', + itemHeight: controlHeightLG, + groupTitleLineHeight: lineHeight, + collapsedWidth: controlHeightLG * 2, + popupBg: colorBgElevated, + itemMarginBlock: marginXXS, + itemPaddingInline: padding, + horizontalLineHeight: `${controlHeightLG * 1.15}px`, + iconSize: fontSize, + iconMarginInlineEnd: controlHeightSM - fontSize, + collapsedIconSize: fontSizeLG, + groupTitleFontSize: fontSize, + + // Disabled + darkItemDisabledColor: new TinyColor(colorTextLightSolid).setAlpha(0.25).toRgbString(), + + // Dark + darkItemColor: colorTextDark, + darkDangerItemColor: colorError, + darkItemBg: '#001529', + darkPopupBg: '#001529', + darkSubMenuItemBg: '#000c17', + darkItemSelectedColor: colorTextLightSolid, + darkItemSelectedBg: colorPrimary, + darkDangerItemSelectedBg: colorError, + darkItemHoverBg: 'transparent', + darkGroupTitleColor: colorTextDark, + darkItemHoverColor: colorTextLightSolid, + darkDangerItemHoverColor: colorErrorHover, + darkDangerItemSelectedColor: colorTextLightSolid, + darkDangerItemActiveBg: colorError, + + // internal + itemWidth: activeBarWidth + ? `calc(100% + ${activeBarBorderWidth}px)` + : `calc(100% - ${itemMarginInline * 2}px)`, + }; +}; - const menuArrowSize = (fontSize / 7) * 5; +// ============================== Export ============================== +export default ( + prefixCls: Ref, + rootCls: Ref = prefixCls, + injectStyle?: Ref, +) => { + const useStyle = genStyleHooks( + 'Menu', + token => { + const { + colorBgElevated, + controlHeightLG, + fontSize, + darkItemColor, + darkDangerItemColor, + darkItemBg, + darkSubMenuItemBg, + darkItemSelectedColor, + darkItemSelectedBg, + darkDangerItemSelectedBg, + darkItemHoverBg, + darkGroupTitleColor, + darkItemHoverColor, + darkItemDisabledColor, + darkDangerItemHoverColor, + darkDangerItemSelectedColor, + darkDangerItemActiveBg, + popupBg, + darkPopupBg, + } = token; + + const menuArrowSize = token.calc(fontSize).div(7).mul(5).equal(); // Menu Token - const menuToken = mergeToken(token, { - menuItemHeight: controlHeightLG, - menuItemPaddingInline: token.margin, + const menuToken = mergeToken(token, { menuArrowSize, - menuHorizontalHeight: controlHeightLG * 1.15, - menuArrowOffset: `${menuArrowSize * 0.25}px`, - menuPanelMaskInset: -7, // Still a hardcode here since it's offset by rc-align + menuHorizontalHeight: token.calc(controlHeightLG).mul(1.15).equal(), + menuArrowOffset: token.calc(menuArrowSize).mul(0.25).equal(), menuSubMenuBg: colorBgElevated, + calc: token.calc, + popupBg, }); - const colorTextDark = new TinyColor(colorTextLightSolid).setAlpha(0.65).toRgbString(); - - const menuDarkToken = mergeToken( - menuToken, - { - colorItemText: colorTextDark, - colorItemTextHover: colorTextLightSolid, - colorGroupTitle: colorTextDark, - colorItemTextSelected: colorTextLightSolid, - colorItemBg: '#001529', - colorSubItemBg: '#000c17', - colorItemBgActive: 'transparent', - colorItemBgSelected: colorPrimary, - colorActiveBarWidth: 0, - colorActiveBarHeight: 0, - colorActiveBarBorderSize: 0, - - // Disabled - colorItemTextDisabled: new TinyColor(colorTextLightSolid).setAlpha(0.25).toRgbString(), - - // Danger - colorDangerItemText: colorError, - colorDangerItemTextHover: colorErrorHover, - colorDangerItemTextSelected: colorTextLightSolid, - colorDangerItemBgActive: colorError, - colorDangerItemBgSelected: colorError, - - menuSubMenuBg: '#001529', - - // Horizontal - colorItemTextSelectedHorizontal: colorTextLightSolid, - colorItemBgSelectedHorizontal: colorPrimary, - }, - { - ...overrideComponentToken, - }, - ); + const menuDarkToken = mergeToken(menuToken, { + itemColor: darkItemColor, + itemHoverColor: darkItemHoverColor, + groupTitleColor: darkGroupTitleColor, + itemSelectedColor: darkItemSelectedColor, + subMenuItemSelectedColor: darkItemSelectedColor, + itemBg: darkItemBg, + popupBg: darkPopupBg, + subMenuItemBg: darkSubMenuItemBg, + itemActiveBg: 'transparent', + itemSelectedBg: darkItemSelectedBg, + activeBarHeight: 0, + activeBarBorderWidth: 0, + itemHoverBg: darkItemHoverBg, + + // Disabled + itemDisabledColor: darkItemDisabledColor, + + // Danger + dangerItemColor: darkDangerItemColor, + dangerItemHoverColor: darkDangerItemHoverColor, + dangerItemSelectedColor: darkDangerItemSelectedColor, + dangerItemActiveBg: darkDangerItemActiveBg, + dangerItemSelectedBg: darkDangerItemSelectedBg, + + menuSubMenuBg: darkSubMenuItemBg, + + // Horizontal + horizontalItemSelectedColor: darkItemSelectedColor, + horizontalItemSelectedBg: darkItemSelectedBg, + }); return [ // Basic @@ -520,58 +1075,40 @@ export default (prefixCls: Ref, injectStyle?: Ref): UseComponen initZoomMotion(menuToken, 'zoom-big'), ]; }, - token => { - const { - colorPrimary, - colorError, - colorTextDisabled, - colorErrorBg, - colorText, - colorTextDescription, - colorBgContainer, - colorFillAlter, - colorFillContent, - lineWidth, - lineWidthBold, - controlItemBgActive, - colorBgTextHover, - } = token; - - return { - dropdownWidth: 160, - zIndexPopup: token.zIndexPopupBase + 50, - radiusItem: token.borderRadiusLG, - radiusSubMenuItem: token.borderRadiusSM, - colorItemText: colorText, - colorItemTextHover: colorText, - colorItemTextHoverHorizontal: colorPrimary, - colorGroupTitle: colorTextDescription, - colorItemTextSelected: colorPrimary, - colorItemTextSelectedHorizontal: colorPrimary, - colorItemBg: colorBgContainer, - colorItemBgHover: colorBgTextHover, - colorItemBgActive: colorFillContent, - colorSubItemBg: colorFillAlter, - colorItemBgSelected: controlItemBgActive, - colorItemBgSelectedHorizontal: 'transparent', - colorActiveBarWidth: 0, - colorActiveBarHeight: lineWidthBold, - colorActiveBarBorderSize: lineWidth, - - // Disabled - colorItemTextDisabled: colorTextDisabled, - - // Danger - colorDangerItemText: colorError, - colorDangerItemTextHover: colorError, - colorDangerItemTextSelected: colorError, - colorDangerItemBgActive: colorErrorBg, - colorDangerItemBgSelected: colorErrorBg, - - itemMarginInline: token.marginXXS, - }; + prepareComponentToken, + { + deprecatedTokens: [ + ['colorGroupTitle', 'groupTitleColor'], + ['radiusItem', 'itemBorderRadius'], + ['radiusSubMenuItem', 'subMenuItemBorderRadius'], + ['colorItemText', 'itemColor'], + ['colorItemTextHover', 'itemHoverColor'], + ['colorItemTextHoverHorizontal', 'horizontalItemHoverColor'], + ['colorItemTextSelected', 'itemSelectedColor'], + ['colorItemTextSelectedHorizontal', 'horizontalItemSelectedColor'], + ['colorItemTextDisabled', 'itemDisabledColor'], + ['colorDangerItemText', 'dangerItemColor'], + ['colorDangerItemTextHover', 'dangerItemHoverColor'], + ['colorDangerItemTextSelected', 'dangerItemSelectedColor'], + ['colorDangerItemBgActive', 'dangerItemActiveBg'], + ['colorDangerItemBgSelected', 'dangerItemSelectedBg'], + ['colorItemBg', 'itemBg'], + ['colorItemBgHover', 'itemHoverBg'], + ['colorSubItemBg', 'subMenuItemBg'], + ['colorItemBgActive', 'itemActiveBg'], + ['colorItemBgSelectedHorizontal', 'horizontalItemSelectedBg'], + ['colorActiveBarWidth', 'activeBarWidth'], + ['colorActiveBarHeight', 'activeBarHeight'], + ['colorActiveBarBorderSize', 'activeBarBorderWidth'], + ['colorItemBgSelected', 'itemSelectedBg'], + ], + // Dropdown will handle menu style self. We do not need to handle this. + injectStyle: injectStyle?.value, + unitless: { + groupTitleLineHeight: true, + }, }, ); - return useOriginHook(prefixCls); + return useStyle(prefixCls, rootCls); }; diff --git a/components/menu/style/rtl.ts b/components/menu/style/rtl.ts index a13fd7d8df..04807adf61 100644 --- a/components/menu/style/rtl.ts +++ b/components/menu/style/rtl.ts @@ -1,7 +1,14 @@ +import { unit } from '../../_util/cssinjs'; +import type { CSSUtil } from '../../theme/util/genComponentStyleHook'; + import type { MenuToken } from '.'; import type { GenerateStyle } from '../../theme/internal'; -const getRTLStyle: GenerateStyle = ({ componentCls, menuArrowOffset }) => ({ +const getRTLStyle: GenerateStyle = ({ + componentCls, + menuArrowOffset, + calc, +}) => ({ [`${componentCls}-rtl`]: { direction: 'rtl', }, @@ -15,11 +22,11 @@ const getRTLStyle: GenerateStyle = ({ componentCls, menuArrowOffset } ${componentCls}-submenu-rtl ${componentCls}-vertical`]: { [`${componentCls}-submenu-arrow`]: { '&::before': { - transform: `rotate(-45deg) translateY(-${menuArrowOffset})`, + transform: `rotate(-45deg) translateY(${unit(calc(menuArrowOffset).mul(-1).equal())})`, }, '&::after': { - transform: `rotate(45deg) translateY(${menuArrowOffset})`, + transform: `rotate(45deg) translateY(${unit(menuArrowOffset)})`, }, }, }, diff --git a/components/menu/style/theme.ts b/components/menu/style/theme.ts index d59ad5adca..6cea307683 100644 --- a/components/menu/style/theme.ts +++ b/components/menu/style/theme.ts @@ -1,6 +1,7 @@ -import type { CSSInterpolation } from '../../_util/cssinjs'; -import { genFocusOutline } from '../../style'; +import { unit, CSSInterpolation } from '../../_util/cssinjs'; + import type { MenuToken } from '.'; +import { genFocusOutline } from '../../style'; const accessibilityFocus = (token: MenuToken) => ({ ...genFocusOutline(token), @@ -9,108 +10,121 @@ const accessibilityFocus = (token: MenuToken) => ({ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation => { const { componentCls, - colorItemText, - colorItemTextSelected, - colorGroupTitle, - colorItemBg, - colorSubItemBg, - colorItemBgSelected, - colorActiveBarHeight, - colorActiveBarWidth, - colorActiveBarBorderSize, + itemColor, + itemSelectedColor, + subMenuItemSelectedColor, + groupTitleColor, + itemBg, + subMenuItemBg, + itemSelectedBg, + activeBarHeight, + activeBarWidth, + activeBarBorderWidth, motionDurationSlow, motionEaseInOut, motionEaseOut, - menuItemPaddingInline, + itemPaddingInline, motionDurationMid, - colorItemTextHover, + itemHoverColor, lineType, colorSplit, // Disabled - colorItemTextDisabled, + itemDisabledColor, // Danger - colorDangerItemText, - colorDangerItemTextHover, - colorDangerItemTextSelected, - colorDangerItemBgActive, - colorDangerItemBgSelected, - - colorItemBgHover, + dangerItemColor, + dangerItemHoverColor, + dangerItemSelectedColor, + dangerItemActiveBg, + dangerItemSelectedBg, + // Bg + popupBg, + itemHoverBg, + itemActiveBg, menuSubMenuBg, // Horizontal - colorItemTextSelectedHorizontal, - colorItemBgSelectedHorizontal, + horizontalItemSelectedColor, + horizontalItemSelectedBg, + horizontalItemBorderRadius, + horizontalItemHoverBg, } = token; return { - [`${componentCls}-${themeSuffix}`]: { - color: colorItemText, - background: colorItemBg, + [`${componentCls}-${themeSuffix}, ${componentCls}-${themeSuffix} > ${componentCls}`]: { + color: itemColor, + background: itemBg, [`&${componentCls}-root:focus-visible`]: { ...accessibilityFocus(token), }, // ======================== Item ======================== - [`${componentCls}-item-group-title`]: { - color: colorGroupTitle, + [`${componentCls}-item`]: { + '&-group-title, &-extra': { + color: groupTitleColor, + }, }, - [`${componentCls}-submenu-selected`]: { - [`> ${componentCls}-submenu-title`]: { - color: colorItemTextSelected, + [`${componentCls}-submenu-selected > ${componentCls}-submenu-title`]: { + color: subMenuItemSelectedColor, + }, + + [`${componentCls}-item, ${componentCls}-submenu-title`]: { + color: itemColor, + [`&:not(${componentCls}-item-disabled):focus-visible`]: { + ...accessibilityFocus(token), }, }, // Disabled [`${componentCls}-item-disabled, ${componentCls}-submenu-disabled`]: { - color: `${colorItemTextDisabled} !important`, + color: `${itemDisabledColor} !important`, }, // Hover - [`${componentCls}-item:hover, ${componentCls}-submenu-title:hover`]: { - [`&:not(${componentCls}-item-selected):not(${componentCls}-submenu-selected)`]: { - color: colorItemTextHover, + [`${componentCls}-item:not(${componentCls}-item-selected):not(${componentCls}-submenu-selected)`]: + { + [`&:hover, > ${componentCls}-submenu-title:hover`]: { + color: itemHoverColor, + }, }, - }, [`&:not(${componentCls}-horizontal)`]: { [`${componentCls}-item:not(${componentCls}-item-selected)`]: { '&:hover': { - backgroundColor: colorItemBgHover, + backgroundColor: itemHoverBg, }, '&:active': { - backgroundColor: colorItemBgSelected, + backgroundColor: itemActiveBg, }, }, [`${componentCls}-submenu-title`]: { '&:hover': { - backgroundColor: colorItemBgHover, + backgroundColor: itemHoverBg, }, '&:active': { - backgroundColor: colorItemBgSelected, + backgroundColor: itemActiveBg, }, }, }, // Danger - only Item has [`${componentCls}-item-danger`]: { - color: colorDangerItemText, + color: dangerItemColor, [`&${componentCls}-item:hover`]: { [`&:not(${componentCls}-item-selected):not(${componentCls}-submenu-selected)`]: { - color: colorDangerItemTextHover, + color: dangerItemHoverColor, }, }, [`&${componentCls}-item:active`]: { - background: colorDangerItemBgActive, + background: dangerItemActiveBg, }, }, @@ -121,30 +135,24 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation }, [`${componentCls}-item-selected`]: { - color: colorItemTextSelected, + color: itemSelectedColor, // Danger [`&${componentCls}-item-danger`]: { - color: colorDangerItemTextSelected, + color: dangerItemSelectedColor, }, - [`a, a:hover`]: { + 'a, a:hover': { color: 'inherit', }, }, [`& ${componentCls}-item-selected`]: { - backgroundColor: colorItemBgSelected, + backgroundColor: itemSelectedBg, // Danger [`&${componentCls}-item-danger`]: { - backgroundColor: colorDangerItemBgSelected, - }, - }, - - [`${componentCls}-item, ${componentCls}-submenu-title`]: { - [`&:not(${componentCls}-item-disabled):focus-visible`]: { - ...accessibilityFocus(token), + backgroundColor: dangerItemSelectedBg, }, }, @@ -152,9 +160,16 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation backgroundColor: menuSubMenuBg, }, + // ===== 设置浮层的颜色 ======= + // !dark 模式会被popupBg 会被rest 为 darkPopupBg [`&${componentCls}-popup > ${componentCls}`]: { - backgroundColor: colorItemBg, + backgroundColor: popupBg, + }, + + [`&${componentCls}-submenu-popup > ${componentCls}`]: { + backgroundColor: popupBg, }, + // ===== 设置浮层的颜色 end ======= // ====================== Horizontal ====================== [`&${componentCls}-horizontal`]: { @@ -165,32 +180,36 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation : {}), [`> ${componentCls}-item, > ${componentCls}-submenu`]: { - top: colorActiveBarBorderSize, - marginTop: -colorActiveBarBorderSize, + top: activeBarBorderWidth, + marginTop: token.calc(activeBarBorderWidth).mul(-1).equal(), marginBottom: 0, - borderRadius: 0, + borderRadius: horizontalItemBorderRadius, '&::after': { position: 'absolute', - insetInline: menuItemPaddingInline, + insetInline: itemPaddingInline, bottom: 0, - borderBottom: `${colorActiveBarHeight}px solid transparent`, + borderBottom: `${unit(activeBarHeight)} solid transparent`, transition: `border-color ${motionDurationSlow} ${motionEaseInOut}`, content: '""', }, - [`&:hover, &-active, &-open`]: { + '&:hover, &-active, &-open': { + background: horizontalItemHoverBg, '&::after': { - borderBottomWidth: colorActiveBarHeight, - borderBottomColor: colorItemTextSelectedHorizontal, + borderBottomWidth: activeBarHeight, + borderBottomColor: horizontalItemSelectedColor, }, }, - [`&-selected`]: { - color: colorItemTextSelectedHorizontal, - backgroundColor: colorItemBgSelectedHorizontal, + '&-selected': { + color: horizontalItemSelectedColor, + backgroundColor: horizontalItemSelectedBg, + '&:hover': { + backgroundColor: horizontalItemSelectedBg, + }, '&::after': { - borderBottomWidth: colorActiveBarHeight, - borderBottomColor: colorItemTextSelectedHorizontal, + borderBottomWidth: activeBarHeight, + borderBottomColor: horizontalItemSelectedColor, }, }, }, @@ -200,7 +219,7 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation // [`&${componentCls}-root`]: { [`&${componentCls}-inline, &${componentCls}-vertical`]: { - borderInlineEnd: `${colorActiveBarBorderSize}px ${lineType} ${colorSplit}`, + borderInlineEnd: `${unit(activeBarBorderWidth)} ${lineType} ${colorSplit}`, }, }, @@ -208,17 +227,9 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation [`&${componentCls}-inline`]: { // Sub [`${componentCls}-sub${componentCls}-inline`]: { - background: colorSubItemBg, + background: subMenuItemBg, }, - // Item - [`${componentCls}-item, ${componentCls}-submenu-title`]: - colorActiveBarBorderSize && colorActiveBarWidth - ? { - width: `calc(100% + ${colorActiveBarBorderSize}px)`, - } - : {}, - [`${componentCls}-item`]: { position: 'relative', @@ -226,7 +237,7 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation position: 'absolute', insetBlock: 0, insetInlineEnd: 0, - borderInlineEnd: `${colorActiveBarWidth}px solid ${colorItemTextSelected}`, + borderInlineEnd: `${unit(activeBarWidth)} solid ${itemSelectedColor}`, transform: 'scaleY(0.0001)', opacity: 0, transition: [ @@ -239,7 +250,7 @@ const getThemeStyle = (token: MenuToken, themeSuffix: string): CSSInterpolation // Danger [`&${componentCls}-item-danger`]: { '&::after': { - borderInlineEndColor: colorDangerItemTextSelected, + borderInlineEndColor: dangerItemSelectedColor, }, }, }, diff --git a/components/menu/style/vertical.ts b/components/menu/style/vertical.ts index 874e7126fc..72daae829c 100644 --- a/components/menu/style/vertical.ts +++ b/components/menu/style/vertical.ts @@ -1,47 +1,44 @@ -import type { CSSObject } from '../../_util/cssinjs'; -import { textEllipsis } from '../../style'; +import { unit, CSSObject } from '../../_util/cssinjs'; import type { MenuToken } from '.'; +import { textEllipsis } from '../../style'; import type { GenerateStyle } from '../../theme/internal'; const getVerticalInlineStyle: GenerateStyle = token => { const { componentCls, - menuItemHeight, + itemHeight, itemMarginInline, padding, menuArrowSize, marginXS, - marginXXS, + itemMarginBlock, + itemWidth, + itemPaddingInline, } = token; - const paddingWithArrow = padding + menuArrowSize + marginXS; + const paddingWithArrow = token.calc(menuArrowSize).add(padding).add(marginXS).equal(); return { [`${componentCls}-item`]: { position: 'relative', + overflow: 'hidden', }, [`${componentCls}-item, ${componentCls}-submenu-title`]: { - height: menuItemHeight, - lineHeight: `${menuItemHeight}px`, - paddingInline: padding, + height: itemHeight, + lineHeight: unit(itemHeight), + paddingInline: itemPaddingInline, overflow: 'hidden', textOverflow: 'ellipsis', - marginInline: itemMarginInline, - marginBlock: marginXXS, - width: `calc(100% - ${itemMarginInline * 2}px)`, - }, - - // disable margin collapsed - [`${componentCls}-submenu`]: { - paddingBottom: 0.02, + marginBlock: itemMarginBlock, + width: itemWidth, }, [`> ${componentCls}-item, > ${componentCls}-submenu > ${componentCls}-submenu-title`]: { - height: menuItemHeight, - lineHeight: `${menuItemHeight}px`, + height: itemHeight, + lineHeight: unit(itemHeight), }, [`${componentCls}-item-group-list ${componentCls}-submenu-title, @@ -55,23 +52,25 @@ const getVerticalStyle: GenerateStyle = token => { const { componentCls, iconCls, - menuItemHeight, + itemHeight, colorTextLightSolid, dropdownWidth, controlHeightLG, - motionDurationMid, motionEaseOut, paddingXL, - fontSizeSM, + itemMarginInline, fontSizeLG, + motionDurationFast, motionDurationSlow, paddingXS, boxShadowSecondary, + collapsedWidth, + collapsedIconSize, } = token; const inlineItemStyle: CSSObject = { - height: menuItemHeight, - lineHeight: `${menuItemHeight}px`, + height: itemHeight, + lineHeight: unit(itemHeight), listStylePosition: 'inside', listStyleType: 'disc', }; @@ -79,7 +78,7 @@ const getVerticalStyle: GenerateStyle = token => { return [ { [componentCls]: { - [`&-inline, &-vertical`]: { + '&-inline, &-vertical': { [`&${componentCls}-root`]: { boxShadow: 'none', }, @@ -100,7 +99,7 @@ const getVerticalStyle: GenerateStyle = token => { { [`${componentCls}-submenu-popup ${componentCls}-vertical${componentCls}-sub`]: { minWidth: dropdownWidth, - maxHeight: `calc(100vh - ${controlHeightLG * 2.5}px)`, + maxHeight: `calc(100vh - ${unit(token.calc(controlHeightLG).mul(2.5).equal())})`, padding: '0', overflow: 'hidden', borderInlineEnd: 0, @@ -127,7 +126,7 @@ const getVerticalStyle: GenerateStyle = token => { transition: [ `border-color ${motionDurationSlow}`, `background ${motionDurationSlow}`, - `padding ${motionDurationMid} ${motionEaseOut}`, + `padding ${motionDurationFast} ${motionEaseOut}`, ].join(','), [`> ${componentCls}-title-content`]: { @@ -165,7 +164,7 @@ const getVerticalStyle: GenerateStyle = token => { // Inline Collapse Only { [`${componentCls}-inline-collapsed`]: { - width: menuItemHeight * 2, + width: collapsedWidth, [`&${componentCls}-root`]: { [`${componentCls}-item, ${componentCls}-submenu ${componentCls}-submenu-title`]: { @@ -181,7 +180,9 @@ const getVerticalStyle: GenerateStyle = token => { > ${componentCls}-item-group > ${componentCls}-item-group-list > ${componentCls}-submenu > ${componentCls}-submenu-title, > ${componentCls}-submenu > ${componentCls}-submenu-title`]: { insetInlineStart: 0, - paddingInline: `calc(50% - ${fontSizeSM}px)`, + paddingInline: `calc(50% - ${unit(token.calc(collapsedIconSize).div(2).equal())} - ${unit( + itemMarginInline, + )})`, textOverflow: 'clip', [` @@ -193,8 +194,8 @@ const getVerticalStyle: GenerateStyle = token => { [`${componentCls}-item-icon, ${iconCls}`]: { margin: 0, - fontSize: fontSizeLG, - lineHeight: `${menuItemHeight}px`, + fontSize: collapsedIconSize, + lineHeight: unit(itemHeight), '+ span': { display: 'inline-block',