feat(badge): migrate less to token (#42778)

* chore: update

* docs: add component token demo

* test: update snapshot

* chore: update

* test: update snapshot

* feat: token

* chore: update snapshot

* chore: code clean

* chore: code clean

* chore: code clean

* chore: code clean

* chore: update

* chore: fix lint

* fix: fontsizesm

---------

Co-authored-by: MadCcc <1075746765@qq.com>
This commit is contained in:
2023-08-14 17:18:42 +08:00
committed by GitHub
parent db07a2fe0a
commit 6a6f1b741f
10 changed files with 466 additions and 73 deletions

View File

@@ -1390,6 +1390,147 @@ Array [
exports[`renders components/badge/demo/colorful-with-count-debug.tsx extend context correctly 2`] = `[]`;
exports[`renders components/badge/demo/component-token.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom: 8px;"
>
<span
class="ant-badge"
>
<span
class="ant-avatar ant-avatar-lg ant-avatar-square"
>
<span
class="ant-avatar-string"
style="transform: scale(1) translateX(-50%);"
/>
</span>
<sup
class="ant-scroll-number ant-badge-count"
data-show="true"
title="5"
>
<span
class="ant-scroll-number-only"
style="transition: none;"
>
<span
class="ant-scroll-number-only-unit current"
>
5
</span>
</span>
</sup>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom: 8px;"
>
<span
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
data-show="true"
title="26"
>
<span
class="ant-scroll-number-only"
style="transition: none;"
>
<span
class="ant-scroll-number-only-unit current"
>
2
</span>
</span>
<span
class="ant-scroll-number-only"
style="transition: none;"
>
<span
class="ant-scroll-number-only-unit current"
>
6
</span>
</span>
</sup>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom: 8px;"
>
<span
class="ant-badge"
>
<span
aria-label="notification"
class="anticon anticon-notification"
role="img"
>
<svg
aria-hidden="true"
data-icon="notification"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112c-3.8 0-7.7.7-11.6 2.3L292 345.9H128c-8.8 0-16 7.4-16 16.6v299c0 9.2 7.2 16.6 16 16.6h101.7c-3.7 11.6-5.7 23.9-5.7 36.4 0 65.9 53.8 119.5 120 119.5 55.4 0 102.1-37.6 115.9-88.4l408.6 164.2c3.9 1.5 7.8 2.3 11.6 2.3 16.9 0 32-14.2 32-33.2V145.2C912 126.2 897 112 880 112zM344 762.3c-26.5 0-48-21.4-48-47.8 0-11.2 3.9-21.9 11-30.4l84.9 34.1c-2 24.6-22.7 44.1-47.9 44.1zm496 58.4L318.8 611.3l-12.9-5.2H184V417.9h121.9l12.9-5.2L840 203.3v617.4z"
/>
</svg>
</span>
<sup
class="ant-scroll-number ant-badge-dot"
data-show="true"
/>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom: 8px;"
>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-success"
/>
<span
class="ant-badge-status-text"
>
Success
</span>
</span>
</div>
<div
class="ant-space-item"
>
<span
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-count-sm"
data-show="true"
title="0"
>
0
</sup>
</span>
</div>
</div>
`;
exports[`renders components/badge/demo/component-token.tsx extend context correctly 2`] = `[]`;
exports[`renders components/badge/demo/dot.tsx extend context correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center"

View File

@@ -1383,6 +1383,145 @@ Array [
]
`;
exports[`renders components/badge/demo/component-token.tsx correctly 1`] = `
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<span
class="ant-badge"
>
<span
class="ant-avatar ant-avatar-lg ant-avatar-square"
>
<span
class="ant-avatar-string"
style="opacity:0"
/>
</span>
<sup
class="ant-scroll-number ant-badge-count"
data-show="true"
title="5"
>
<span
class="ant-scroll-number-only"
style="transition:none"
>
<span
class="ant-scroll-number-only-unit current"
>
5
</span>
</span>
</sup>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<span
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-multiple-words"
data-show="true"
title="26"
>
<span
class="ant-scroll-number-only"
style="transition:none"
>
<span
class="ant-scroll-number-only-unit current"
>
2
</span>
</span>
<span
class="ant-scroll-number-only"
style="transition:none"
>
<span
class="ant-scroll-number-only-unit current"
>
6
</span>
</span>
</sup>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<span
class="ant-badge"
>
<span
aria-label="notification"
class="anticon anticon-notification"
role="img"
>
<svg
aria-hidden="true"
data-icon="notification"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 112c-3.8 0-7.7.7-11.6 2.3L292 345.9H128c-8.8 0-16 7.4-16 16.6v299c0 9.2 7.2 16.6 16 16.6h101.7c-3.7 11.6-5.7 23.9-5.7 36.4 0 65.9 53.8 119.5 120 119.5 55.4 0 102.1-37.6 115.9-88.4l408.6 164.2c3.9 1.5 7.8 2.3 11.6 2.3 16.9 0 32-14.2 32-33.2V145.2C912 126.2 897 112 880 112zM344 762.3c-26.5 0-48-21.4-48-47.8 0-11.2 3.9-21.9 11-30.4l84.9 34.1c-2 24.6-22.7 44.1-47.9 44.1zm496 58.4L318.8 611.3l-12.9-5.2H184V417.9h121.9l12.9-5.2L840 203.3v617.4z"
/>
</svg>
</span>
<sup
class="ant-scroll-number ant-badge-dot"
data-show="true"
/>
</span>
</div>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-success"
/>
<span
class="ant-badge-status-text"
>
Success
</span>
</span>
</div>
<div
class="ant-space-item"
>
<span
class="ant-badge ant-badge-not-a-wrapper"
>
<sup
class="ant-scroll-number ant-badge-count ant-badge-count-sm"
data-show="true"
title="0"
>
0
</sup>
</span>
</div>
</div>
`;
exports[`renders components/badge/demo/dot.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center"

View File

@@ -0,0 +1,7 @@
## zh-CN
Component Token Debug.
## en-US
Component Token Debug

View File

@@ -0,0 +1,32 @@
import { NotificationOutlined } from '@ant-design/icons';
import React from 'react';
import { Avatar, Badge, ConfigProvider, Space } from 'antd';
/** Test usage. Do not use in your production. */
export default () => (
<ConfigProvider
theme={{
components: {
Badge: {
indicatorHeight: 24,
indicatorHeightSM: 18,
dotSize: 4,
textFontWeight: 'bold',
statusSize: 8,
},
},
}}
>
<Space direction="vertical">
<Badge count={5}>
<Avatar shape="square" size="large" />
</Badge>
<Badge count={26} />
<Badge dot>
<NotificationOutlined />
</Badge>
<Badge status="success" text="Success" />
<Badge size="small" count={0} showZero />
</Space>
</ConfigProvider>
);

View File

@@ -32,6 +32,7 @@ Badge normally appears in proximity to notifications or user avatars with eye-ca
<code src="./demo/mix.tsx" debug>Mixed usage</code>
<code src="./demo/title.tsx" debug>Title</code>
<code src="./demo/colorful-with-count-debug.tsx" debug>Colorful Badge support count Debug</code>
<code src="./demo/component-token.tsx" debug>Component Token</code>
## API

View File

@@ -33,6 +33,7 @@ group: 数据展示
<code src="./demo/mix.tsx" debug>各种混用的情况</code>
<code src="./demo/title.tsx" debug>自定义标题</code>
<code src="./demo/colorful-with-count-debug.tsx" debug>多彩徽标支持 count 显示 Debug</code>
<code src="./demo/component-token.tsx" debug>组件 Token</code>
## API

View File

@@ -4,19 +4,56 @@ import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, genPresetColor, mergeToken } from '../../theme/internal';
/** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken {
// Component token here
/**
* @desc 徽标 z-index
* @descEN z-index of badge
*/
indicatorZIndex: number | string;
/**
* @desc 徽标高度
* @descEN Height of badge
*/
indicatorHeight: number;
/**
* @desc 小号徽标高度
* @descEN Height of small badge
*/
indicatorHeightSM: number;
/**
* @desc 点状徽标尺寸
* @descEN Size of dot badge
*/
dotSize: number;
/**
* @desc 徽标文本尺寸
* @descEN Font size of badge text
*/
textFontSize: number;
/**
* @desc 小号徽标文本尺寸
* @descEN Font size of small badge text
*/
textFontSizeSM: number;
/**
* @desc 徽标文本粗细
* @descEN Font weight of badge text
*/
textFontWeight: number | string;
/**
* @desc 状态徽标尺寸
* @descEN Size of status badge
*/
statusSize: number;
}
interface BadgeToken extends FullToken<'Badge'> {
badgeFontHeight: number;
badgeZIndex: number | string;
badgeHeight: number;
badgeHeightSm: number;
badgeTextColor: string;
badgeFontWeight: string;
badgeFontSize: number;
badgeColor: string;
badgeColorHover: string;
badgeDotSize: number;
badgeFontSizeSm: number;
badgeStatusSize: number;
badgeShadowSize: number;
badgeShadowColor: string;
badgeProcessingDuration: string;
@@ -63,9 +100,14 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
antCls,
badgeFontHeight,
badgeShadowSize,
badgeHeightSm,
motionDurationSlow,
badgeStatusSize,
textFontSize,
textFontSizeSM,
statusSize,
dotSize,
textFontWeight,
indicatorHeight,
indicatorHeightSM,
marginXS,
badgeRibbonOffset,
} = token;
@@ -98,17 +140,17 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
lineHeight: 1,
[`${componentCls}-count`]: {
zIndex: token.badgeZIndex,
minWidth: token.badgeHeight,
height: token.badgeHeight,
zIndex: token.indicatorZIndex,
minWidth: indicatorHeight,
height: indicatorHeight,
color: token.badgeTextColor,
fontWeight: token.badgeFontWeight,
fontSize: token.badgeFontSize,
lineHeight: `${token.badgeHeight}px`,
fontWeight: textFontWeight,
fontSize: textFontSize,
lineHeight: `${indicatorHeight}px`,
whiteSpace: 'nowrap',
textAlign: 'center',
background: token.badgeColor,
borderRadius: token.badgeHeight / 2,
borderRadius: indicatorHeight / 2,
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.badgeShadowColor}`,
transition: `background ${token.motionDurationMid}`,
@@ -124,11 +166,11 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
},
},
[`${componentCls}-count-sm`]: {
minWidth: badgeHeightSm,
height: badgeHeightSm,
fontSize: token.badgeFontSizeSm,
lineHeight: `${badgeHeightSm}px`,
borderRadius: badgeHeightSm / 2,
minWidth: indicatorHeightSM,
height: indicatorHeightSM,
fontSize: textFontSizeSM,
lineHeight: `${indicatorHeightSM}px`,
borderRadius: indicatorHeightSM / 2,
},
[`${componentCls}-multiple-words`]: {
@@ -136,10 +178,10 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
},
[`${componentCls}-dot`]: {
zIndex: token.badgeZIndex,
width: token.badgeDotSize,
minWidth: token.badgeDotSize,
height: token.badgeDotSize,
zIndex: token.indicatorZIndex,
width: dotSize,
minWidth: dotSize,
height: dotSize,
background: token.badgeColor,
borderRadius: '100%',
boxShadow: `0 0 0 ${badgeShadowSize}px ${token.badgeShadowColor}`,
@@ -168,8 +210,8 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
position: 'relative',
top: -1, // Magic number, but seems better experience
display: 'inline-block',
width: badgeStatusSize,
height: badgeStatusSize,
width: statusSize,
height: statusSize,
verticalAlign: 'middle',
borderRadius: '50%',
},
@@ -259,12 +301,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
[`${numberPrefixCls}-only`]: {
position: 'relative',
display: 'inline-block',
height: token.badgeHeight,
height: indicatorHeight,
transition: `all ${token.motionDurationSlow} ${token.motionEaseOutBack}`,
WebkitTransformStyle: 'preserve-3d',
WebkitBackfaceVisibility: 'hidden',
[`> p${numberPrefixCls}-only-unit`]: {
height: token.badgeHeight,
height: indicatorHeight,
margin: 0,
WebkitTransformStyle: 'preserve-3d',
WebkitBackfaceVisibility: 'hidden',
@@ -334,45 +376,46 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
};
// ============================== Export ==============================
export default genComponentStyleHook('Badge', (token) => {
const { fontSize, lineHeight, fontSizeSM, lineWidth, marginXS, colorBorderBg } = token;
export default genComponentStyleHook(
'Badge',
(token) => {
const { fontSize, lineHeight, lineWidth, marginXS, colorBorderBg } = token;
const badgeFontHeight = Math.round(fontSize * lineHeight);
const badgeShadowSize = lineWidth;
const badgeZIndex = 'auto';
const badgeHeight = badgeFontHeight - 2 * badgeShadowSize;
const badgeTextColor = token.colorBgContainer;
const badgeFontWeight = 'normal';
const badgeFontSize = fontSizeSM;
const badgeColor = token.colorError;
const badgeColorHover = token.colorErrorHover;
const badgeHeightSm = fontSize;
const badgeDotSize = fontSizeSM / 2;
const badgeFontSizeSm = fontSizeSM;
const badgeStatusSize = fontSizeSM / 2;
const badgeFontHeight = Math.round(fontSize * lineHeight);
const badgeShadowSize = lineWidth;
const badgeTextColor = token.colorBgContainer;
const badgeColor = token.colorError;
const badgeColorHover = token.colorErrorHover;
const badgeToken = mergeToken<BadgeToken>(token, {
badgeFontHeight,
badgeShadowSize,
badgeZIndex,
badgeHeight,
badgeTextColor,
badgeFontWeight,
badgeFontSize,
badgeColor,
badgeColorHover,
badgeShadowColor: colorBorderBg,
badgeHeightSm,
badgeDotSize,
badgeFontSizeSm,
badgeStatusSize,
badgeProcessingDuration: '1.2s',
badgeRibbonOffset: marginXS,
const badgeToken = mergeToken<BadgeToken>(token, {
badgeFontHeight,
badgeShadowSize,
badgeTextColor,
badgeColor,
badgeColorHover,
badgeShadowColor: colorBorderBg,
badgeProcessingDuration: '1.2s',
badgeRibbonOffset: marginXS,
// Follow token just by Design. Not related with token
badgeRibbonCornerTransform: 'scaleY(0.75)',
badgeRibbonCornerFilter: `brightness(75%)`,
});
// Follow token just by Design. Not related with token
badgeRibbonCornerTransform: 'scaleY(0.75)',
badgeRibbonCornerFilter: `brightness(75%)`,
});
return [genSharedBadgeStyle(badgeToken)];
});
return [genSharedBadgeStyle(badgeToken)];
},
(token) => {
const { fontSize, lineHeight, fontSizeSM, lineWidth } = token;
return {
indicatorZIndex: 'auto',
indicatorHeight: Math.round(fontSize * lineHeight) - 2 * lineWidth,
indicatorHeightSM: fontSize,
dotSize: fontSizeSM / 2,
textFontSize: fontSizeSM,
textFontSizeSM: fontSizeSM,
textFontWeight: 'normal',
statusSize: fontSizeSM / 2,
};
},
);

View File

@@ -4,6 +4,7 @@ import type { ComponentToken as AnchorComponentToken } from '../../anchor/style'
import type { ComponentToken as AppComponentToken } from '../../app/style';
import type { ComponentToken as AvatarComponentToken } from '../../avatar/style';
import type { ComponentToken as BackTopComponentToken } from '../../back-top/style';
import type { ComponentToken as BadgeComponentToken } from '../../badge/style';
import type { ComponentToken as BreadcrumbComponentToken } from '../../breadcrumb/style';
import type { ComponentToken as ButtonComponentToken } from '../../button/style';
import type { ComponentToken as CalendarComponentToken } from '../../calendar/style';
@@ -61,7 +62,7 @@ export interface ComponentTokenMap {
Anchor?: AnchorComponentToken;
Avatar?: AvatarComponentToken;
BackTop?: BackTopComponentToken;
Badge?: {};
Badge?: BadgeComponentToken;
Button?: ButtonComponentToken;
Breadcrumb?: BreadcrumbComponentToken;
Card?: CardComponentToken;

View File

@@ -14,8 +14,8 @@ This document contains the correspondence between all the less variables related
We could configure global token and component token for each component through the `theme` property of ConfigProvider.
```tsx
import React from 'react';
import { Checkbox, ConfigProvider, Radio } from 'antd';
import React from 'react';
const App: React.FC = () => (
<ConfigProvider
@@ -73,7 +73,21 @@ export default App;
| `@avatar-group-space` | `groupSpace` | - |
| `@avatar-group-border-color` | `colorBorderBg` | Global Token |
<!-- ### Badge -->
### Badge
<!-- prettier-ignore -->
| Less variables | Component Token | Note |
| --- | --- | --- |
| `@zindex-badge` | `indicatorZIndex` | - |
| `@badge-height` | `indicatorHeight` | - |
| `@badge-height-sm` | `indicatorHeightSM` | - |
| `@badge-dot-size` | `dotSize` | - |
| `@badge-font-size` | `textFontSize` | - |
| `@badge-font-size-sm` | `textFontSizeSM` | - |
| `@badge-font-weight` | `textFontWeight` | - |
| `@badge-status-size` | `statusSize` | - |
| `@badge-text-color` | `colorBgContainer` | Global Token |
| `@badge-color` | `colorError` | Global Token |
### BreadCrumb

View File

@@ -14,8 +14,8 @@ title: 从 Less 变量到 Design Token
通过 ConfigProvider 的 `theme` 属性,我们可以对每一个组件单独配置全局 Token 和组件 Token
```tsx
import React from 'react';
import { Checkbox, ConfigProvider, Radio } from 'antd';
import React from 'react';
const App: React.FC = () => (
<ConfigProvider
@@ -73,7 +73,21 @@ export default App;
| `@avatar-group-space` | `groupSpace` | - |
| `@avatar-group-border-color` | `colorBorderBg` | 全局 Token |
<!-- ### Badge 徽标数 -->
### Badge 徽标数
<!-- prettier-ignore -->
| less 变量 | Component Token | 备注 |
| --- | --- | --- |
| `@zindex-badge` | `indicatorZIndex` | - |
| `@badge-height` | `indicatorHeight` | - |
| `@badge-height-sm` | `indicatorHeightSM` | - |
| `@badge-dot-size` | `dotSize` | - |
| `@badge-font-size` | `textFontSize` | - |
| `@badge-font-size-sm` | `textFontSizeSM` | - |
| `@badge-font-weight` | `textFontWeight` | - |
| `@badge-status-size` | `statusSize` | - |
| `@badge-text-color` | `colorBgContainer` | 全局 Token |
| `@badge-color` | `colorError` | 全局 Token |
### BreadCrumb 面包屑