feat: float button support badge (#6738)
* docs(FloatButton): add badge demo * fix(Badge): color attribute invalidpull/6757/head
parent
4ea318be30
commit
7591d5c3e6
|
@ -107,7 +107,7 @@ export default defineComponent({
|
|||
const statusCls = computed(() => ({
|
||||
[`${prefixCls.value}-status-dot`]: hasStatus.value,
|
||||
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
|
||||
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
|
||||
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
|
||||
}));
|
||||
|
||||
const statusStyle = computed(() => {
|
||||
|
@ -125,7 +125,7 @@ export default defineComponent({
|
|||
[`${prefixCls.value}-multiple-words`]:
|
||||
!isDotRef.value && displayCount.value && displayCount.value.toString().length > 1,
|
||||
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
|
||||
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
|
||||
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
|
||||
}));
|
||||
|
||||
return () => {
|
||||
|
|
|
@ -73,9 +73,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
const ribbonPrefixCls = `${antCls}-ribbon`;
|
||||
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
|
||||
|
||||
const statusPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`${componentCls}-status-${colorKey}`]: {
|
||||
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
|
||||
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
|
||||
background: darkColor,
|
||||
[`&:not(${componentCls}-count)`]: {
|
||||
color: darkColor,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -150,9 +153,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
insetInlineEnd: 0,
|
||||
transform: 'translate(50%, -50%)',
|
||||
transformOrigin: '100% 0%',
|
||||
[`${iconCls}-spin`]: {
|
||||
[`&${iconCls}-spin`]: {
|
||||
animationName: antBadgeLoadingCircle,
|
||||
animationDuration: token.motionDurationMid,
|
||||
animationDuration: '1s',
|
||||
animationIterationCount: 'infinite',
|
||||
animationTimingFunction: 'linear',
|
||||
},
|
||||
|
@ -207,13 +210,13 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
[`${componentCls}-status-warning`]: {
|
||||
backgroundColor: token.colorWarning,
|
||||
},
|
||||
...statusPreset,
|
||||
[`${componentCls}-status-text`]: {
|
||||
marginInlineStart: marginXS,
|
||||
color: token.colorText,
|
||||
fontSize: token.fontSize,
|
||||
},
|
||||
},
|
||||
...colorPreset,
|
||||
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
|
||||
animationName: antZoomBadgeIn,
|
||||
animationDuration: token.motionDurationSlow,
|
||||
|
@ -284,7 +287,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
|
|||
...resetComponent(token),
|
||||
position: 'absolute',
|
||||
top: marginXS,
|
||||
height: badgeFontHeight,
|
||||
padding: `0 ${token.paddingXS}px`,
|
||||
color: token.colorPrimary,
|
||||
lineHeight: `${badgeFontHeight}px`,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import classNames from '../_util/classNames';
|
||||
import { defineComponent, computed, ref } from 'vue';
|
||||
import Tooltip from '../tooltip';
|
||||
import Badge from '../badge';
|
||||
import Content from './FloatButtonContent';
|
||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||
import { useInjectFloatButtonGroupContext } from './context';
|
||||
|
@ -37,6 +38,7 @@ const FloatButton = defineComponent({
|
|||
shape = 'circle',
|
||||
description = slots.description?.(),
|
||||
tooltip,
|
||||
badge = {},
|
||||
...restProps
|
||||
} = props;
|
||||
|
||||
|
@ -60,15 +62,17 @@ const FloatButton = defineComponent({
|
|||
? () => (slots.tooltip && slots.tooltip()) || tooltip
|
||||
: undefined,
|
||||
default: () => (
|
||||
<div class={`${prefixCls.value}-body`}>
|
||||
<Content
|
||||
prefixCls={prefixCls.value}
|
||||
v-slots={{
|
||||
icon: slots.icon,
|
||||
description: () => description,
|
||||
}}
|
||||
></Content>
|
||||
</div>
|
||||
<Badge {...badge}>
|
||||
<div class={`${prefixCls.value}-body`}>
|
||||
<Content
|
||||
prefixCls={prefixCls.value}
|
||||
v-slots={{
|
||||
icon: slots.icon,
|
||||
description: () => description,
|
||||
}}
|
||||
></Content>
|
||||
</div>
|
||||
</Badge>
|
||||
),
|
||||
}}
|
||||
></Tooltip>
|
||||
|
|
|
@ -20,6 +20,44 @@ exports[`renders ./components/float-button/demo/back-top.vue correctly 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/float-button/demo/badge.vue correctly 1`] = `
|
||||
<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>
|
||||
</div>
|
||||
</div><sup data-show="true" class="ant-scroll-number ant-badge-dot"></sup>
|
||||
<!----></span>
|
||||
<!---->
|
||||
</button>
|
||||
<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>
|
||||
</div>
|
||||
</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>
|
||||
<!----></span>
|
||||
<!----></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>
|
||||
</div>
|
||||
</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>
|
||||
<!----></span>
|
||||
<!---->
|
||||
</button></div>
|
||||
<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>
|
||||
<!---->
|
||||
</div>
|
||||
</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>
|
||||
<!----></span>
|
||||
<!----></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>
|
||||
</div>
|
||||
</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>
|
||||
<!----></span>
|
||||
<!---->
|
||||
</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>
|
||||
<!---->
|
||||
</div>
|
||||
</div><sup data-show="false" class="ant-scroll-number ant-badge-count" style="display: none;">
|
||||
<!---->
|
||||
</sup>
|
||||
<!----></span>
|
||||
<!---->
|
||||
</button></div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/float-button/demo/basic.vue correctly 1`] = `
|
||||
<button class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button">
|
||||
<!---->
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<docs>
|
||||
---
|
||||
order: 8
|
||||
iframe: 360
|
||||
title:
|
||||
zh-CN: 徽标数
|
||||
en-US: Badge
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
右上角附带圆形徽标数字的悬浮按钮。
|
||||
|
||||
## en-US
|
||||
|
||||
FloatButton with Badge.
|
||||
|
||||
</docs>
|
||||
|
||||
<template>
|
||||
<a-float-button shape="circle" :badge="{ dot: true }" :style="{ right: '164px' }" />
|
||||
<a-float-button-group shape="circle" :style="{ right: '94px' }">
|
||||
<a-float-button :badge="{ count: 5, color: 'blue' }">
|
||||
<template #tooltip>
|
||||
<div>custom badge color</div>
|
||||
</template>
|
||||
</a-float-button>
|
||||
<a-float-button :badge="{ count: 5 }"></a-float-button>
|
||||
</a-float-button-group>
|
||||
<a-float-button-group shape="circle">
|
||||
<a-float-button :badge="{ count: 12 }">
|
||||
<template #icon>
|
||||
<QuestionCircleOutlined />
|
||||
</template>
|
||||
</a-float-button>
|
||||
<a-float-button :badge="{ count: 123, overflowCount: 999 }"></a-float-button>
|
||||
<a-back-top :visibility-height="0" />
|
||||
</a-float-button-group>
|
||||
</template>
|
||||
<script setup>
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons-vue';
|
||||
</script>
|
|
@ -23,6 +23,9 @@
|
|||
<template v-else-if="iframeName === 'backtop'">
|
||||
<back-top></back-top>
|
||||
</template>
|
||||
<template v-else-if="iframeName === 'badge'">
|
||||
<badge></badge>
|
||||
</template>
|
||||
<demo-sort v-else>
|
||||
<basic></basic>
|
||||
<type></type>
|
||||
|
@ -32,6 +35,7 @@
|
|||
<group></group>
|
||||
<group-menu></group-menu>
|
||||
<back-top></back-top>
|
||||
<badge></badge>
|
||||
</demo-sort>
|
||||
</template>
|
||||
|
||||
|
@ -44,6 +48,7 @@ import Tooltip from './tooltip.vue';
|
|||
import group from './group.vue';
|
||||
import GroupMenu from './group-menu.vue';
|
||||
import BackTop from './back-top.vue';
|
||||
import Badge from './badge.vue';
|
||||
|
||||
import { defineComponent, provide } from 'vue';
|
||||
import US from '../index.en-US.md';
|
||||
|
@ -61,6 +66,7 @@ export default defineComponent({
|
|||
group,
|
||||
GroupMenu,
|
||||
BackTop,
|
||||
Badge,
|
||||
},
|
||||
props: {
|
||||
iframeName: String,
|
||||
|
@ -78,6 +84,7 @@ export default defineComponent({
|
|||
'floatbutton-group': '/iframe/float-button/#floatbutton-group',
|
||||
'menu-mode': '/iframe/float-button/#menu-mode',
|
||||
backtop: '/iframe/float-button/#backtop',
|
||||
badge: '/iframe/float-button/#badge',
|
||||
}
|
||||
: {},
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ FloatButton. Available since `4.0.0`.
|
|||
| shape | Setting button shape | `circle` \| `square` | `circle` | |
|
||||
| href | The target of hyperlink | string | - | |
|
||||
| target | Specifies where to display the linked URL | string | - | |
|
||||
| badge | Attach Badge to FloatButton. `status` and other props related are not supported. | [BadgeProps](/components/badge#api) | - | |
|
||||
|
||||
### common events
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*a0hwTY_rOSUAAA
|
|||
| onClick | 点击按钮时的回调 | (event) => void | - | |
|
||||
| href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | |
|
||||
| target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | |
|
||||
| badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | |
|
||||
|
||||
### common events
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { ExtractPropTypes } from 'vue';
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import type { MouseEventHandler } from '../_util/EventInterface';
|
||||
import { stringType, booleanType, functionType } from '../_util/type';
|
||||
import { stringType, booleanType, functionType, objectType } from '../_util/type';
|
||||
import type { BadgeProps } from '../badge';
|
||||
|
||||
export type FloatButtonType = 'default' | 'primary';
|
||||
|
||||
|
@ -9,6 +10,8 @@ export type FloatButtonShape = 'circle' | 'square';
|
|||
|
||||
export type FloatButtonGroupTrigger = 'click' | 'hover';
|
||||
|
||||
export type FloatButtonBadgeProps = Omit<BadgeProps, 'status' | 'text' | 'title' | 'children'>;
|
||||
|
||||
export const floatButtonProps = () => {
|
||||
return {
|
||||
prefixCls: String,
|
||||
|
@ -18,6 +21,7 @@ export const floatButtonProps = () => {
|
|||
tooltip: PropTypes.any,
|
||||
href: String,
|
||||
target: functionType<() => Window | HTMLElement | null>(),
|
||||
badge: objectType<FloatButtonBadgeProps>(),
|
||||
onClick: functionType<MouseEventHandler>(),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@ import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
|||
import { initFadeMotion } from '../../style/motion/fade';
|
||||
import { resetComponent } from '../../style';
|
||||
import { initMotion } from '../../style/motion/motion';
|
||||
import getOffset from '../util';
|
||||
|
||||
/** Component only token. Which will handle additional calculation of alias token */
|
||||
export interface ComponentToken {
|
||||
|
@ -18,6 +19,11 @@ type FloatButtonToken = FullToken<'FloatButton'> & {
|
|||
floatButtonFontSize: number;
|
||||
floatButtonSize: number;
|
||||
floatButtonIconSize: number;
|
||||
floatButtonBodySize: number;
|
||||
floatButtonBodyPadding: number;
|
||||
badgeOffset: number;
|
||||
dotOffsetInCircle: number;
|
||||
dotOffsetInSquare: number;
|
||||
|
||||
// Position
|
||||
floatButtonInsetBlockEnd: number;
|
||||
|
@ -80,7 +86,16 @@ const initFloatButtonGroupMotion = (token: FloatButtonToken) => {
|
|||
|
||||
// ============================== Group ==============================
|
||||
const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token => {
|
||||
const { componentCls, floatButtonSize, margin, borderRadiusLG } = token;
|
||||
const {
|
||||
antCls,
|
||||
componentCls,
|
||||
floatButtonSize,
|
||||
margin,
|
||||
borderRadiusLG,
|
||||
borderRadiusSM,
|
||||
badgeOffset,
|
||||
floatButtonBodyPadding,
|
||||
} = token;
|
||||
const groupPrefixCls = `${componentCls}-group`;
|
||||
return {
|
||||
[groupPrefixCls]: {
|
||||
|
@ -116,6 +131,7 @@ const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
[`${componentCls}-body`]: {
|
||||
width: floatButtonSize,
|
||||
height: floatButtonSize,
|
||||
borderRadius: '50%',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -134,17 +150,22 @@ const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
'&:not(:last-child)': {
|
||||
borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorSplit}`,
|
||||
},
|
||||
[`${antCls}-badge`]: {
|
||||
[`${antCls}-badge-count`]: {
|
||||
top: -(floatButtonBodyPadding + badgeOffset),
|
||||
insetInlineEnd: -(floatButtonBodyPadding + badgeOffset),
|
||||
},
|
||||
},
|
||||
},
|
||||
[`${groupPrefixCls}-wrap`]: {
|
||||
display: 'block',
|
||||
borderRadius: borderRadiusLG,
|
||||
boxShadow: token.boxShadowSecondary,
|
||||
overflow: 'hidden',
|
||||
[`${componentCls}-square`]: {
|
||||
boxShadow: 'none',
|
||||
marginTop: 0,
|
||||
borderRadius: 0,
|
||||
padding: token.paddingXXS,
|
||||
padding: floatButtonBodyPadding,
|
||||
'&:first-child': {
|
||||
borderStartStartRadius: borderRadiusLG,
|
||||
borderStartEndRadius: borderRadiusLG,
|
||||
|
@ -157,8 +178,8 @@ const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
borderBottom: `${token.lineWidth}px ${token.lineType} ${token.colorSplit}`,
|
||||
},
|
||||
[`${componentCls}-body`]: {
|
||||
width: floatButtonSize - token.paddingXXS * 2,
|
||||
height: floatButtonSize - token.paddingXXS * 2,
|
||||
width: token.floatButtonBodySize,
|
||||
height: token.floatButtonBodySize,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -171,10 +192,11 @@ const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
boxShadow: token.boxShadowSecondary,
|
||||
[`${componentCls}-square`]: {
|
||||
boxShadow: 'none',
|
||||
padding: token.paddingXXS,
|
||||
padding: floatButtonBodyPadding,
|
||||
[`${componentCls}-body`]: {
|
||||
width: floatButtonSize - token.paddingXXS * 2,
|
||||
height: floatButtonSize - token.paddingXXS * 2,
|
||||
width: token.floatButtonBodySize,
|
||||
height: token.floatButtonBodySize,
|
||||
borderRadius: borderRadiusSM,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -183,14 +205,23 @@ const floatButtonGroupStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
|
||||
// ============================== Shared ==============================
|
||||
const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token => {
|
||||
const { componentCls, floatButtonIconSize, floatButtonSize, borderRadiusLG } = token;
|
||||
const {
|
||||
antCls,
|
||||
componentCls,
|
||||
floatButtonBodyPadding,
|
||||
floatButtonIconSize,
|
||||
floatButtonSize,
|
||||
borderRadiusLG,
|
||||
badgeOffset,
|
||||
dotOffsetInSquare,
|
||||
dotOffsetInCircle,
|
||||
} = token;
|
||||
return {
|
||||
[componentCls]: {
|
||||
...resetComponent(token),
|
||||
border: 'none',
|
||||
position: 'fixed',
|
||||
cursor: 'pointer',
|
||||
overflow: 'hidden',
|
||||
zIndex: 99,
|
||||
display: 'block',
|
||||
justifyContent: 'center',
|
||||
|
@ -210,7 +241,16 @@ const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
'&:empty': {
|
||||
display: 'none',
|
||||
},
|
||||
|
||||
[`${antCls}-badge`]: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
[`${antCls}-badge-count`]: {
|
||||
transform: 'translate(0, 0)',
|
||||
transformOrigin: 'center',
|
||||
top: -badgeOffset,
|
||||
insetInlineEnd: -badgeOffset,
|
||||
},
|
||||
},
|
||||
[`${componentCls}-body`]: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
@ -226,7 +266,7 @@ const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: `2px 4px`,
|
||||
padding: `${floatButtonBodyPadding / 2}px ${floatButtonBodyPadding}px`,
|
||||
[`${componentCls}-icon`]: {
|
||||
textAlign: 'center',
|
||||
margin: 'auto',
|
||||
|
@ -237,9 +277,18 @@ const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
},
|
||||
},
|
||||
},
|
||||
[`${componentCls}-rtl`]: {
|
||||
direction: 'rtl',
|
||||
},
|
||||
[`${componentCls}-circle`]: {
|
||||
height: floatButtonSize,
|
||||
borderRadius: '50%',
|
||||
[`${antCls}-badge`]: {
|
||||
[`${antCls}-badge-dot`]: {
|
||||
top: dotOffsetInCircle,
|
||||
insetInlineEnd: dotOffsetInCircle,
|
||||
},
|
||||
},
|
||||
[`${componentCls}-body`]: {
|
||||
borderRadius: '50%',
|
||||
},
|
||||
|
@ -248,9 +297,15 @@ const sharedFloatButtonStyle: GenerateStyle<FloatButtonToken, CSSObject> = token
|
|||
height: 'auto',
|
||||
minHeight: floatButtonSize,
|
||||
borderRadius: borderRadiusLG,
|
||||
[`${antCls}-badge`]: {
|
||||
[`${antCls}-badge-dot`]: {
|
||||
top: dotOffsetInSquare,
|
||||
insetInlineEnd: dotOffsetInSquare,
|
||||
},
|
||||
},
|
||||
[`${componentCls}-body`]: {
|
||||
height: 'auto',
|
||||
borderRadius: token.borderRadiusSM,
|
||||
borderRadius: borderRadiusLG,
|
||||
},
|
||||
},
|
||||
[`${componentCls}-default`]: {
|
||||
|
@ -312,6 +367,8 @@ export default genComponentStyleHook<'FloatButton'>('FloatButton', token => {
|
|||
fontSize,
|
||||
fontSizeIcon,
|
||||
controlItemBgHover,
|
||||
paddingXXS,
|
||||
borderRadiusLG,
|
||||
} = token;
|
||||
const floatButtonToken = mergeToken<FloatButtonToken>(token, {
|
||||
floatButtonBackgroundColor: colorBgElevated,
|
||||
|
@ -323,6 +380,12 @@ export default genComponentStyleHook<'FloatButton'>('FloatButton', token => {
|
|||
|
||||
floatButtonInsetBlockEnd: marginXXL,
|
||||
floatButtonInsetInlineEnd: marginLG,
|
||||
floatButtonBodySize: controlHeightLG - paddingXXS * 2,
|
||||
// 这里的 paddingXXS 是简写,完整逻辑是 (controlHeightLG - (controlHeightLG - paddingXXS * 2)) / 2,
|
||||
floatButtonBodyPadding: paddingXXS,
|
||||
badgeOffset: paddingXXS * 1.5,
|
||||
dotOffsetInCircle: getOffset(controlHeightLG / 2),
|
||||
dotOffsetInSquare: getOffset(borderRadiusLG),
|
||||
});
|
||||
return [
|
||||
floatButtonGroupStyle(floatButtonToken),
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
const getOffset = (radius: number): number => {
|
||||
if (radius === 0) {
|
||||
return 0;
|
||||
}
|
||||
// 如果要考虑通用性,这里应该用三角函数 Math.sin(45)
|
||||
// 但是这个场景比较特殊,始终是等腰直角三角形,所以直接用 Math.sqrt() 开方即可
|
||||
return radius - Math.sqrt(radius ** 2 / 2);
|
||||
};
|
||||
|
||||
export default getOffset;
|
Loading…
Reference in New Issue