Skip to content

Commit 9d43a91

Browse files
feat(Badge): the shape attr add four optional values (#855)
* feat(Badge): the shape attr add four optional values * feat(Badge): update demo * docs: regenerate api docs * fix: fix test unit * chore: update _common * fix: fix demo * chore: update common * chore: update _common * fix: fix cr --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 1daac67 commit 9d43a91

File tree

13 files changed

+790
-222
lines changed

13 files changed

+790
-222
lines changed

src/avatar/__tests__/avatar.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('Avatar', () => {
4343
const count = 8;
4444
const { container } = render(<Avatar badgeProps={{ count, offset: [6, 6] }} icon={<UserIcon />} />);
4545
expect(container.querySelector('.t-badge--basic')).toBeTruthy();
46-
expect(container.querySelector('.t-badge--basic').innerHTML.trim()).toBe(`${count}`);
46+
expect(container.querySelector('.t-badge--basic > .t-badge__count').innerHTML.trim()).toBe(`${count}`);
4747
});
4848

4949
it(': size', () => {

src/badge/Badge.tsx

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@ import { usePrefixClass } from '../hooks/useClass';
1111

1212
export interface BadgeProps extends TdBadgeProps, StyledProps {}
1313

14-
const hasUnit = (unit: string) =>
15-
unit.indexOf('px') > 0 ||
16-
unit.indexOf('rpx') > 0 ||
17-
unit.indexOf('em') > 0 ||
18-
unit.indexOf('rem') > 0 ||
19-
unit.indexOf('%') > 0 ||
20-
unit.indexOf('vh') > 0 ||
21-
unit.indexOf('vm') > 0;
14+
const hasUnit = (value: string): boolean => /px|rpx|em|rem|%|vh|vw/.test(value);
15+
16+
const addUnit = (value: string | number): string => {
17+
const strValue = value.toString();
18+
return hasUnit(strValue) ? strValue : `${value}px`;
19+
};
2220

2321
const Badge = forwardRef<HTMLDivElement, BadgeProps>((originProps, ref) => {
2422
const props = useDefaultProps(originProps, badgeDefaultProps);
@@ -27,22 +25,38 @@ const Badge = forwardRef<HTMLDivElement, BadgeProps>((originProps, ref) => {
2725
const { classPrefix } = useConfig();
2826
const badgeClass = usePrefixClass('badge');
2927

28+
const childNode = content || children;
29+
3030
// 徽标自定义样式
3131
const badgeInnerStyles = useMemo(() => {
32-
const mergedStyle: React.CSSProperties = {};
33-
if (color) mergedStyle.backgroundColor = color;
34-
if (offset && Array.isArray(offset)) {
35-
const [right = 0, top = 0]: Array<string | number> = offset;
36-
mergedStyle.right = hasUnit(right.toString()) ? right : `${right}px`;
37-
mergedStyle.top = hasUnit(top.toString()) ? top : `${top}px`;
32+
const styles: React.CSSProperties = {};
33+
if (color) styles.backgroundColor = color;
34+
const [xOffset = 0, yOffset = 0]: Array<string | number> = offset || [];
35+
36+
if (xOffset) {
37+
styles.left = `calc(100% + ${addUnit(xOffset)})`;
38+
}
39+
40+
if (yOffset) {
41+
styles.top = addUnit(yOffset);
3842
}
39-
return mergedStyle;
43+
44+
return styles;
4045
}, [color, offset]);
4146

47+
// 是否使用外层类名
48+
const useOuterClass = useMemo(() => {
49+
const target = ['ribbon', 'ribbon-right', 'ribbon-left', 'triangle-right', 'triangle-left'];
50+
if (content || !target.includes(shape)) {
51+
return false;
52+
}
53+
return !parseTNode(childNode);
54+
}, [content, shape, childNode]);
55+
4256
// 徽标外层样式类
4357
const badgeClasses = classNames(className, {
4458
[`${badgeClass}`]: true,
45-
[`${badgeClass}__ribbon-outer`]: shape === 'ribbon',
59+
[`${badgeClass}__${shape}-outer`]: useOuterClass,
4660
});
4761

4862
// 徽标内层样式类
@@ -78,8 +92,6 @@ const Badge = forwardRef<HTMLDivElement, BadgeProps>((originProps, ref) => {
7892
return parseTNode(count);
7993
}, [dot, count, maxCount, showZero]);
8094

81-
const childNode = content || children;
82-
8395
const readerContent = () => {
8496
if (typeof content === 'string') {
8597
return <span className={`${badgeClass}__content-text`}>{content}</span>;
@@ -91,7 +103,7 @@ const Badge = forwardRef<HTMLDivElement, BadgeProps>((originProps, ref) => {
91103
if (!isShowBadge) return null;
92104
return (
93105
<div className={badgeInnerClasses} style={badgeInnerStyles}>
94-
{readerCount}
106+
<div className={`${badgeClass}__count`}>{readerCount}</div>
95107
</div>
96108
);
97109
};

src/badge/__tests__/index.test.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@ describe('Badge', () => {
5353

5454
it(':count', () => {
5555
const { container } = render(<Badge count={99} />);
56-
expect(container.querySelector('.t-badge--basic').innerHTML.trim()).toBe('99');
56+
expect(container.querySelector('.t-badge--basic > .t-badge__count').innerHTML.trim()).toBe('99');
5757
const { container: container2 } = render(<Badge count={() => 33} />);
58-
expect(container2.querySelector('.t-badge--basic').innerHTML.trim()).toBe('33');
58+
expect(container2.querySelector('.t-badge--basic > .t-badge__count').innerHTML.trim()).toBe('33');
5959
const { container: container3 } = render(<Badge count={null} />);
60-
expect(container3.querySelector('.t-badge--basic')).toBe(null);
60+
expect(container3.querySelector('.t-badge--basic > .t-badge__count')).toBe(null);
6161
});
6262

6363
it(':dot', () => {
@@ -67,21 +67,19 @@ describe('Badge', () => {
6767

6868
it(':maxCount', () => {
6969
const { container } = render(<Badge count={100} maxCount={99} />);
70-
expect(container.querySelector('.t-badge--basic').innerHTML.trim()).toBe('99+');
70+
expect(container.querySelector('.t-badge--basic > .t-badge__count').innerHTML.trim()).toBe('99+');
7171
});
7272

7373
it(':offset', () => {
7474
const { container } = render(<Badge count={3} offset={[10, 10]} />);
7575
expect(container.querySelector('.t-badge--basic').getAttribute('style'))
76-
.contain('right: 10px;')
76+
.contain('left: calc(100% + 10px);')
7777
.contain('top: 10px;');
7878
const { container: container1 } = render(<Badge count={3} offset={[]} />);
79-
expect(container1.querySelector('.t-badge--basic').getAttribute('style'))
80-
.contain('right: 0px;')
81-
.contain('top: 0px;');
79+
expect(container1.querySelector('.t-badge--basic').getAttribute('style')).toBe(null);
8280
const { container: container2 } = render(<Badge count={3} offset={['10em', '10rem']} />);
8381
expect(container2.querySelector('.t-badge--basic').getAttribute('style'))
84-
.contain('right: 10em;')
82+
.contain('left: calc(100% + 10em);')
8583
.contain('top: 10rem;');
8684
});
8785

src/badge/_example/base.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ export default function BaseBadge() {
1818

1919
<div className="summary">数字徽标</div>
2020
<div className="badge-demo">
21-
<Badge count="8" content="消息" offset={[-8, 0]} className="badge-item" />
22-
<Badge count="2" offset={[-2, -2]} className="badge-item">
21+
<Badge count="8" content="消息" offset={[4, 0]} className="badge-item" />
22+
<Badge count="2" offset={[2, -2]} className="badge-item">
2323
<NotificationIcon size={24} />
2424
</Badge>
2525
<Badge count="8" offset={[2, 2]} className="badge-item">

src/badge/_example/size.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default function SizeBadge() {
1010
<Avatar icon={<UserIcon />} size="large" badgeProps={{ count: 8, size: 'large', offset: [7, 7] }} />
1111
</div>
1212

13-
<div className="summary">Middle</div>
13+
<div className="summary">Medium</div>
1414
<div className="block">
1515
<Avatar icon={<UserIcon />} badgeProps={{ count: 8, offset: [5, 5] }} />
1616
</div>

src/badge/_example/theme.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ export default function ThemeBadge() {
77
<>
88
<div className="summary">圆形徽标</div>
99
<div className="badge-demo">
10-
<Badge count="2" offset={[-2, -2]}>
10+
<Badge count="2" offset={[2, -2]}>
1111
<NotificationIcon size={24} />
1212
</Badge>
1313
</div>
1414

1515
<div className="summary">方形徽标</div>
1616
<div className="badge-demo">
17-
<Badge count="2" shape="square" offset={[-2, -2]}>
17+
<Badge count="2" shape="square" offset={[1, -2]}>
1818
<NotificationIcon size={24} />
1919
</Badge>
2020
</div>
@@ -29,7 +29,18 @@ export default function ThemeBadge() {
2929
<div className="summary" style={{ marginBottom: '16px' }}>
3030
角标
3131
</div>
32-
<Cell title="单行标题" note={<Badge count="New" offset={[0, 0]} shape="ribbon" />}></Cell>
32+
<Cell title="单行标题" note={<Badge count="NEW" offset={[0, 0]} shape="ribbon-left" />}></Cell>
33+
<Cell title="单行标题" bordered={false} note={<Badge count="NEW" offset={[0, 0]} shape="ribbon" />}></Cell>
34+
35+
<div className="summary" style={{ marginBottom: '16px' }}>
36+
三角角标
37+
</div>
38+
<Cell title="单行标题" note={<Badge count="NEW" offset={[0, 0]} shape="triangle-left" />}></Cell>
39+
<Cell
40+
title="单行标题"
41+
bordered={false}
42+
note={<Badge count="NEW" offset={[0, 0]} shape="triangle-right" />}
43+
></Cell>
3344
</>
3445
);
3546
}

src/badge/badge.en-US.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@
22

33
## API
44

5-
65
### Badge Props
76

87
name | type | default | description | required
98
-- | -- | -- | -- | --
109
className | String | - | className of component | N
11-
style | Object | - | CSS(Cascading Style Sheets),Typescript`React.CSSProperties` | N
12-
children | TNode | - | Typescript`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
10+
style | Object | - | CSS(Cascading Style Sheets),Typescript: `React.CSSProperties` | N
11+
children | TNode | - | Typescript: `string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
1312
color | String | - | \- | N
14-
content | TNode | - | Typescript`string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
15-
count | TNode | 0 | Typescript`string \| number \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
13+
content | TNode | - | Typescript: `string \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
14+
count | TNode | 0 | Typescript: `string \| number \| TNode`[see more ts definition](https://github.com/Tencent/tdesign-mobile-react/blob/develop/src/common.ts) | N
1615
dot | Boolean | false | \- | N
1716
maxCount | Number | 99 | \- | N
18-
offset | Array | - | Typescript`Array<string \| number>` | N
19-
shape | String | circle | options: circle/square/bubble/ribbon | N
17+
offset | Array | - | Typescript: `Array<string \| number>` | N
18+
shape | String | circle | options: circle/square/bubble/ribbon/ribbon-right/ribbon-left/triangle-right/triangle-left | N
2019
showZero | Boolean | false | \- | N
2120
size | String | medium | options: medium/large | N
2221

@@ -31,9 +30,10 @@ Name | Default Value | Description
3130
--td-badge-bg-color | @error-color | -
3231
--td-badge-border-radius | 2px | -
3332
--td-badge-bubble-border-radius | 10px 10px 10px 1px | -
33+
--td-badge-content-text-color | @text-color-primary | -
3434
--td-badge-dot-size | 8px | -
3535
--td-badge-font | @font-mark-extraSmall | -
3636
--td-badge-large-font | @font-mark-small | -
3737
--td-badge-large-height | 20px | -
3838
--td-badge-large-padding | 5px | -
39-
--td-badge-text-color | @font-white-1 | -
39+
--td-badge-text-color | @text-color-anti | -

src/badge/badge.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ count | TNode | 0 | 徽标右上角内容。可以是数字,也可以是文字
1515
dot | Boolean | false | 是否为红点 | N
1616
maxCount | Number | 99 | 封顶的数字值 | N
1717
offset | Array | - | 设置状态点的位置偏移,示例:[-10, 20]['10em', '8rem']。TS 类型:`Array<string \| number>` | N
18-
shape | String | circle | 形状。可选项:circle/square/bubble/ribbon | N
18+
shape | String | circle | 徽标形状,其中 ribbon 和 ribbon-right 等效。可选项:circle/square/bubble/ribbon/ribbon-right/ribbon-left/triangle-right/triangle-left | N
1919
showZero | Boolean | false | 当数值为 0 时,是否展示徽标 | N
2020
size | String | medium | 尺寸。可选项:medium/large | N
2121

@@ -30,9 +30,10 @@ size | String | medium | 尺寸。可选项:medium/large | N
3030
--td-badge-bg-color | @error-color | -
3131
--td-badge-border-radius | 2px | -
3232
--td-badge-bubble-border-radius | 10px 10px 10px 1px | -
33+
--td-badge-content-text-color | @text-color-primary | -
3334
--td-badge-dot-size | 8px | -
3435
--td-badge-font | @font-mark-extraSmall | -
3536
--td-badge-large-font | @font-mark-small | -
3637
--td-badge-large-height | 20px | -
3738
--td-badge-large-padding | 5px | -
38-
--td-badge-text-color | @font-white-1 | -
39+
--td-badge-text-color | @text-color-anti | -

src/badge/type.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,18 @@ export interface TdBadgeProps {
4040
*/
4141
offset?: Array<string | number>;
4242
/**
43-
* 形状
43+
* 徽标形状,其中 ribbon 和 ribbon-right 等效
4444
* @default circle
4545
*/
46-
shape?: 'circle' | 'square' | 'bubble' | 'ribbon';
46+
shape?:
47+
| 'circle'
48+
| 'square'
49+
| 'bubble'
50+
| 'ribbon'
51+
| 'ribbon-right'
52+
| 'ribbon-left'
53+
| 'triangle-right'
54+
| 'triangle-left';
4755
/**
4856
* 当数值为 0 时,是否展示徽标
4957
* @default false

0 commit comments

Comments
 (0)