Skip to content

Commit 7591d5c

Browse files
authored
feat: float button support badge (#6738)
* docs(FloatButton): add badge demo * fix(Badge): color attribute invalid
1 parent 4ea318b commit 7591d5c

File tree

11 files changed

+203
-31
lines changed

11 files changed

+203
-31
lines changed

components/badge/Badge.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ export default defineComponent({
107107
const statusCls = computed(() => ({
108108
[`${prefixCls.value}-status-dot`]: hasStatus.value,
109109
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
110-
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
110+
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
111111
}));
112112

113113
const statusStyle = computed(() => {
@@ -125,7 +125,7 @@ export default defineComponent({
125125
[`${prefixCls.value}-multiple-words`]:
126126
!isDotRef.value && displayCount.value && displayCount.value.toString().length > 1,
127127
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
128-
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
128+
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
129129
}));
130130

131131
return () => {

components/badge/style/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
7373
const ribbonPrefixCls = `${antCls}-ribbon`;
7474
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
7575

76-
const statusPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
77-
[`${componentCls}-status-${colorKey}`]: {
76+
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
77+
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
7878
background: darkColor,
79+
[`&:not(${componentCls}-count)`]: {
80+
color: darkColor,
81+
},
7982
},
8083
}));
8184

@@ -150,9 +153,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
150153
insetInlineEnd: 0,
151154
transform: 'translate(50%, -50%)',
152155
transformOrigin: '100% 0%',
153-
[`${iconCls}-spin`]: {
156+
[`&${iconCls}-spin`]: {
154157
animationName: antBadgeLoadingCircle,
155-
animationDuration: token.motionDurationMid,
158+
animationDuration: '1s',
156159
animationIterationCount: 'infinite',
157160
animationTimingFunction: 'linear',
158161
},
@@ -207,13 +210,13 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
207210
[`${componentCls}-status-warning`]: {
208211
backgroundColor: token.colorWarning,
209212
},
210-
...statusPreset,
211213
[`${componentCls}-status-text`]: {
212214
marginInlineStart: marginXS,
213215
color: token.colorText,
214216
fontSize: token.fontSize,
215217
},
216218
},
219+
...colorPreset,
217220
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
218221
animationName: antZoomBadgeIn,
219222
animationDuration: token.motionDurationSlow,
@@ -284,7 +287,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
284287
...resetComponent(token),
285288
position: 'absolute',
286289
top: marginXS,
287-
height: badgeFontHeight,
288290
padding: `0 ${token.paddingXS}px`,
289291
color: token.colorPrimary,
290292
lineHeight: `${badgeFontHeight}px`,

components/float-button/FloatButton.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import classNames from '../_util/classNames';
22
import { defineComponent, computed, ref } from 'vue';
33
import Tooltip from '../tooltip';
4+
import Badge from '../badge';
45
import Content from './FloatButtonContent';
56
import useConfigInject from '../config-provider/hooks/useConfigInject';
67
import { useInjectFloatButtonGroupContext } from './context';
@@ -37,6 +38,7 @@ const FloatButton = defineComponent({
3738
shape = 'circle',
3839
description = slots.description?.(),
3940
tooltip,
41+
badge = {},
4042
...restProps
4143
} = props;
4244

@@ -60,15 +62,17 @@ const FloatButton = defineComponent({
6062
? () => (slots.tooltip && slots.tooltip()) || tooltip
6163
: undefined,
6264
default: () => (
63-
<div class={`${prefixCls.value}-body`}>
64-
<Content
65-
prefixCls={prefixCls.value}
66-
v-slots={{
67-
icon: slots.icon,
68-
description: () => description,
69-
}}
70-
></Content>
71-
</div>
65+
<Badge {...badge}>
66+
<div class={`${prefixCls.value}-body`}>
67+
<Content
68+
prefixCls={prefixCls.value}
69+
v-slots={{
70+
icon: slots.icon,
71+
description: () => description,
72+
}}
73+
></Content>
74+
</div>
75+
</Badge>
7276
),
7377
}}
7478
></Tooltip>

components/float-button/__tests__/__snapshots__/demo.test.js.snap

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,44 @@ exports[`renders ./components/float-button/demo/back-top.vue correctly 1`] = `
2020
</div>
2121
`;
2222

23+
exports[`renders ./components/float-button/demo/badge.vue correctly 1`] = `
24+
<button style="right: 164px;" class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="file-text" class="anticon anticon-file-text"><svg focusable="false" class="" data-icon="file-text" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"></path></svg></span></div>
25+
</div>
26+
</div><sup data-show="true" class="ant-scroll-number ant-badge-dot"></sup>
27+
<!----></span>
28+
<!---->
29+
</button>
30+
<div style="right: 94px;" class="ant-float-btn-group ant-float-btn-group-circle ant-float-btn-group-circle-shadow"><button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="file-text" class="anticon anticon-file-text"><svg focusable="false" class="" data-icon="file-text" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"></path></svg></span></div>
31+
</div>
32+
</div><sup data-show="true" class="ant-scroll-number ant-badge-count ant-badge-color-blue" title="5"><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">5</p></span></sup>
33+
<!----></span>
34+
<!----></button><button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="file-text" class="anticon anticon-file-text"><svg focusable="false" class="" data-icon="file-text" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"></path></svg></span></div>
35+
</div>
36+
</div><sup data-show="true" class="ant-scroll-number ant-badge-count" title="5"><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">5</p></span></sup>
37+
<!----></span>
38+
<!---->
39+
</button></div>
40+
<div class="ant-float-btn-group ant-float-btn-group-circle ant-float-btn-group-circle-shadow"><button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="question-circle" class="anticon anticon-question-circle"><svg focusable="false" class="" data-icon="question-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M623.6 316.7C593.6 290.4 554 276 512 276s-81.6 14.5-111.6 40.7C369.2 344 352 380.7 352 420v7.6c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V420c0-44.1 43.1-80 96-80s96 35.9 96 80c0 31.1-22 59.6-56.1 72.7-21.2 8.1-39.2 22.3-52.1 40.9-13.1 19-19.9 41.8-19.9 64.9V620c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8v-22.7a48.3 48.3 0 0130.9-44.8c59-22.7 97.1-74.7 97.1-132.5.1-39.3-17.1-76-48.3-103.3zM472 732a40 40 0 1080 0 40 40 0 10-80 0z"></path></svg></span></div>
41+
<!---->
42+
</div>
43+
</div><sup data-show="true" class="ant-scroll-number ant-badge-count ant-badge-multiple-words" title="12"><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">1</p></span><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">2</p></span></sup>
44+
<!----></span>
45+
<!----></button><button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="file-text" class="anticon anticon-file-text"><svg focusable="false" class="" data-icon="file-text" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M854.6 288.6L639.4 73.4c-6-6-14.1-9.4-22.6-9.4H192c-17.7 0-32 14.3-32 32v832c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V311.3c0-8.5-3.4-16.7-9.4-22.7zM790.2 326H602V137.8L790.2 326zm1.8 562H232V136h302v216a42 42 0 0042 42h216v494zM504 618H320c-4.4 0-8 3.6-8 8v48c0 4.4 3.6 8 8 8h184c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8zM312 490v48c0 4.4 3.6 8 8 8h384c4.4 0 8-3.6 8-8v-48c0-4.4-3.6-8-8-8H320c-4.4 0-8 3.6-8 8z"></path></svg></span></div>
46+
</div>
47+
</div><sup data-show="true" class="ant-scroll-number ant-badge-count ant-badge-multiple-words" title="123"><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">1</p></span><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">2</p></span><span class="ant-scroll-number-only" style="transition: none;"><p class="ant-scroll-number-only-unit current">3</p></span></sup>
48+
<!----></span>
49+
<!---->
50+
</button><button class="ant-float-btn ant-float-btn-default ant-float-btn-circle fade-enter fade-enter-prepare fade-enter-start" type="button"><span class="ant-badge"><div class="ant-float-btn-body"><div class="ant-float-btn-content"><div class="ant-float-btn-icon"><span role="img" aria-label="vertical-align-top" class="anticon anticon-vertical-align-top"><svg focusable="false" class="" data-icon="vertical-align-top" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M859.9 168H164.1c-4.5 0-8.1 3.6-8.1 8v60c0 4.4 3.6 8 8.1 8h695.8c4.5 0 8.1-3.6 8.1-8v-60c0-4.4-3.6-8-8.1-8zM518.3 355a8 8 0 00-12.6 0l-112 141.7a7.98 7.98 0 006.3 12.9h73.9V848c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V509.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 355z"></path></svg></span></div>
51+
<!---->
52+
</div>
53+
</div><sup data-show="false" class="ant-scroll-number ant-badge-count" style="display: none;">
54+
<!---->
55+
</sup>
56+
<!----></span>
57+
<!---->
58+
</button></div>
59+
`;
60+
2361
exports[`renders ./components/float-button/demo/basic.vue correctly 1`] = `
2462
<button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button">
2563
<!---->
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<docs>
2+
---
3+
order: 8
4+
iframe: 360
5+
title:
6+
zh-CN: 徽标数
7+
en-US: Badge
8+
---
9+
10+
## zh-CN
11+
12+
右上角附带圆形徽标数字的悬浮按钮。
13+
14+
## en-US
15+
16+
FloatButton with Badge.
17+
18+
</docs>
19+
20+
<template>
21+
<a-float-button shape="circle" :badge="{ dot: true }" :style="{ right: '164px' }" />
22+
<a-float-button-group shape="circle" :style="{ right: '94px' }">
23+
<a-float-button :badge="{ count: 5, color: 'blue' }">
24+
<template #tooltip>
25+
<div>custom badge color</div>
26+
</template>
27+
</a-float-button>
28+
<a-float-button :badge="{ count: 5 }"></a-float-button>
29+
</a-float-button-group>
30+
<a-float-button-group shape="circle">
31+
<a-float-button :badge="{ count: 12 }">
32+
<template #icon>
33+
<QuestionCircleOutlined />
34+
</template>
35+
</a-float-button>
36+
<a-float-button :badge="{ count: 123, overflowCount: 999 }"></a-float-button>
37+
<a-back-top :visibility-height="0" />
38+
</a-float-button-group>
39+
</template>
40+
<script setup>
41+
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
42+
</script>

components/float-button/demo/index.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
<template v-else-if="iframeName === 'backtop'">
2424
<back-top></back-top>
2525
</template>
26+
<template v-else-if="iframeName === 'badge'">
27+
<badge></badge>
28+
</template>
2629
<demo-sort v-else>
2730
<basic></basic>
2831
<type></type>
@@ -32,6 +35,7 @@
3235
<group></group>
3336
<group-menu></group-menu>
3437
<back-top></back-top>
38+
<badge></badge>
3539
</demo-sort>
3640
</template>
3741

@@ -44,6 +48,7 @@ import Tooltip from './tooltip.vue';
4448
import group from './group.vue';
4549
import GroupMenu from './group-menu.vue';
4650
import BackTop from './back-top.vue';
51+
import Badge from './badge.vue';
4752
4853
import { defineComponent, provide } from 'vue';
4954
import US from '../index.en-US.md';
@@ -61,6 +66,7 @@ export default defineComponent({
6166
group,
6267
GroupMenu,
6368
BackTop,
69+
Badge,
6470
},
6571
props: {
6672
iframeName: String,
@@ -78,6 +84,7 @@ export default defineComponent({
7884
'floatbutton-group': '/iframe/float-button/#floatbutton-group',
7985
'menu-mode': '/iframe/float-button/#menu-mode',
8086
backtop: '/iframe/float-button/#backtop',
87+
badge: '/iframe/float-button/#badge',
8188
}
8289
: {},
8390
);

components/float-button/index.en-US.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ FloatButton. Available since `4.0.0`.
2828
| shape | Setting button shape | `circle` \| `square` | `circle` | |
2929
| href | The target of hyperlink | string | - | |
3030
| target | Specifies where to display the linked URL | string | - | |
31+
| badge | Attach Badge to FloatButton. `status` and other props related are not supported. | [BadgeProps](/components/badge#api) | - | |
3132

3233
### common events
3334

components/float-button/index.zh-CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*a0hwTY_rOSUAAA
3030
| onClick | 点击按钮时的回调 | (event) => void | - | |
3131
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | |
3232
| target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | |
33+
| badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | |
3334

3435
### common events
3536

components/float-button/interface.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import type { ExtractPropTypes } from 'vue';
22
import PropTypes from '../_util/vue-types';
33
import type { MouseEventHandler } from '../_util/EventInterface';
4-
import { stringType, booleanType, functionType } from '../_util/type';
4+
import { stringType, booleanType, functionType, objectType } from '../_util/type';
5+
import type { BadgeProps } from '../badge';
56

67
export type FloatButtonType = 'default' | 'primary';
78

89
export type FloatButtonShape = 'circle' | 'square';
910

1011
export type FloatButtonGroupTrigger = 'click' | 'hover';
1112

13+
export type FloatButtonBadgeProps = Omit<BadgeProps, 'status' | 'text' | 'title' | 'children'>;
14+
1215
export const floatButtonProps = () => {
1316
return {
1417
prefixCls: String,
@@ -18,6 +21,7 @@ export const floatButtonProps = () => {
1821
tooltip: PropTypes.any,
1922
href: String,
2023
target: functionType<() => Window | HTMLElement | null>(),
24+
badge: objectType<FloatButtonBadgeProps>(),
2125
onClick: functionType<MouseEventHandler>(),
2226
};
2327
};

0 commit comments

Comments
 (0)