From 51b973d9d5512930f2651ccbe396add278ad2748 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Mon, 20 Mar 2023 10:28:20 +0800 Subject: [PATCH] feat: FloatButton support Badge (#41040) * feat: FloatButton support internal Badge * update docs * style * update docs * test: update snap * fix * update demo * test: update snap * update style * test: update snap * test: update snap * add docs * fix: update style * update * fix * fix * fix * update style * fix * update demo * add * add docs * snap * test: add test case * Update components/float-button/demo/badge.md Co-authored-by: MadCcc <1075746765@qq.com> * fix * docs: add debug demo * docs: add debug demo * test: update snap * fix border-radius * update snap * fix * fix * rename * style: use paddingXXS * fix * update demo * update snap * demo: add demo --------- Co-authored-by: MadCcc <1075746765@qq.com> --- components/float-button/FloatButton.tsx | 20 +- .../__snapshots__/demo-extend.test.ts.snap | 1976 +++++++++++------ .../__tests__/__snapshots__/demo.test.ts.snap | 1672 +++++++++----- .../__snapshots__/group.test.tsx.snap | 144 +- .../__snapshots__/index.test.tsx.snap | 96 +- .../float-button/__tests__/index.test.tsx | 8 + components/float-button/demo/badge-debug.md | 7 + components/float-button/demo/badge-debug.tsx | 22 + components/float-button/demo/badge.md | 7 + components/float-button/demo/badge.tsx | 20 + components/float-button/demo/render-panel.tsx | 32 +- components/float-button/index.en-US.md | 3 + components/float-button/index.zh-CN.md | 3 + components/float-button/interface.ts | 11 +- components/float-button/style/index.ts | 103 +- components/float-button/util.ts | 10 + 16 files changed, 2763 insertions(+), 1371 deletions(-) create mode 100644 components/float-button/demo/badge-debug.md create mode 100644 components/float-button/demo/badge-debug.tsx create mode 100644 components/float-button/demo/badge.md create mode 100644 components/float-button/demo/badge.tsx create mode 100644 components/float-button/util.ts diff --git a/components/float-button/FloatButton.tsx b/components/float-button/FloatButton.tsx index ac63431edd..0e580c625f 100644 --- a/components/float-button/FloatButton.tsx +++ b/components/float-button/FloatButton.tsx @@ -1,5 +1,7 @@ import classNames from 'classnames'; +import omit from 'rc-util/lib/omit'; import React, { useContext, useMemo } from 'react'; +import Badge from '../badge'; import type { ConfigConsumerProps } from '../config-provider'; import { ConfigContext } from '../config-provider'; import Tooltip from '../tooltip'; @@ -8,6 +10,7 @@ import FloatButtonGroupContext from './context'; import Content from './FloatButtonContent'; import type { CompoundedComponent, + FloatButtonBadgeProps, FloatButtonContentProps, FloatButtonProps, FloatButtonShape, @@ -29,6 +32,7 @@ const FloatButton: React.ForwardRefRenderFunction< icon, description, tooltip, + badge = {}, ...restProps } = props; const { getPrefixCls, direction } = useContext(ConfigContext); @@ -50,16 +54,24 @@ const FloatButton: React.ForwardRefRenderFunction< }, ); + // 虽然在 ts 中已经 omit 过了,但是为了防止多余的属性被透传进来,这里再 omit 一遍,以防万一 + const badgeProps = useMemo( + () => omit(badge, ['title', 'children', 'status', 'text', 'size'] as any[]), + [badge], + ); + const contentProps = useMemo( () => ({ prefixCls, description, icon, type }), [prefixCls, description, icon, type], ); - const buttonNode = ( + const buttonNode: React.ReactNode = ( -
- -
+ +
+ +
+
); diff --git a/components/float-button/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/float-button/__tests__/__snapshots__/demo-extend.test.ts.snap index dc608e3145..773d8e0000 100644 --- a/components/float-button/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/float-button/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -28,68 +28,585 @@ exports[`renders components/float-button/demo/back-top.tsx extend context correc `; -exports[`renders components/float-button/demo/basic.tsx extend context correctly 1`] = ` -, +
+ + +
, +
+ + +
+ +
+
+
+
-
-
+ + , +] +`; + +exports[`renders components/float-button/demo/badge-debug.tsx extend context correctly 1`] = ` +Array [
+
+
+
-
- -`; - -exports[`renders components/float-button/demo/description.tsx extend context correctly 1`] = ` -Array [ +
, , +] +`; + +exports[`renders components/float-button/demo/basic.tsx extend context correctly 1`] = ` +
+
+ +
+
+
+ +
+ +`; + +exports[`renders components/float-button/demo/description.tsx extend context correctly 1`] = ` +Array [ +
+
-
- HELP INFO +
+ HELP INFO +
-
+
- , - , +
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - -
-
- HELP + + +
+
+ HELP +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
-
- +
- - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
-
- - - + + +
-
+
`; -exports[`renders components/float-button/demo/basic.tsx correctly 1`] = ` -
-
- -`; - -exports[`renders components/float-button/demo/description.tsx correctly 1`] = ` -Array [ - , +
-
-
+
+
+ + + +
+
+
+ - + 5 + + + + + + +
, +
+ + +
-
- , + + +
, +] +`; + +exports[`renders components/float-button/demo/badge-debug.tsx correctly 1`] = ` +Array [ +
+
+
+
+
+
, , -
- , -] + + `; -exports[`renders components/float-button/demo/group.tsx correctly 1`] = ` +exports[`renders components/float-button/demo/description.tsx correctly 1`] = ` Array [ -
-
- - , + , +
+ + , +] +`; + +exports[`renders components/float-button/demo/group.tsx correctly 1`] = ` +Array [ +
+
+ + +
,
-
- - - + + +
-
+ , ] @@ -458,37 +932,41 @@ Array [ class="ant-float-btn ant-float-btn-primary ant-float-btn-circle" type="button" > -
- - - + + +
- + ,
-
- - - + + +
-
+ , ] @@ -543,124 +1025,8 @@ exports[`renders components/float-button/demo/render-panel.tsx correctly 1`] = ` class="ant-float-btn ant-float-btn-pure ant-float-btn-default ant-float-btn-circle" type="button" > -
-
-
- - - -
-
-
- - - -
-
- - + - + - + +
-
-
-
+ + + + + + +
+
+
+ +
+ - - + + +`; + +exports[`renders components/float-button/demo/shape.tsx correctly 1`] = ` +Array [ + - - -`; - -exports[`renders components/float-button/demo/shape.tsx correctly 1`] = ` -Array [ + + , , - , -] -`; - -exports[`renders components/float-button/demo/tooltip.tsx correctly 1`] = ` - `; @@ -1053,80 +1587,88 @@ Array [ style="right:24px" type="button" > -
- - - + + +
- + , , ] `; diff --git a/components/float-button/__tests__/__snapshots__/group.test.tsx.snap b/components/float-button/__tests__/__snapshots__/group.test.tsx.snap index d7fafae07c..dd746d94a8 100644 --- a/components/float-button/__tests__/__snapshots__/group.test.tsx.snap +++ b/components/float-button/__tests__/__snapshots__/group.test.tsx.snap @@ -8,109 +8,121 @@ exports[`FloatButtonGroup should correct render 1`] = ` class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button" > -
- - - + + +
- + `; diff --git a/components/float-button/__tests__/__snapshots__/index.test.tsx.snap b/components/float-button/__tests__/__snapshots__/index.test.tsx.snap index c39b483528..4da826f05d 100644 --- a/components/float-button/__tests__/__snapshots__/index.test.tsx.snap +++ b/components/float-button/__tests__/__snapshots__/index.test.tsx.snap @@ -5,37 +5,41 @@ exports[`FloatButton rtl render component should be rendered correctly in RTL di class="ant-float-btn ant-float-btn-default ant-float-btn-circle ant-float-btn-rtl" type="button" > -
- - - + + +
- + `; @@ -44,36 +48,40 @@ exports[`FloatButton should correct render 1`] = ` class="ant-float-btn ant-float-btn-default ant-float-btn-circle" type="button" > -
- - - + + +
- + `; diff --git a/components/float-button/__tests__/index.test.tsx b/components/float-button/__tests__/index.test.tsx index 950d3c6d08..4ab7800b33 100644 --- a/components/float-button/__tests__/index.test.tsx +++ b/components/float-button/__tests__/index.test.tsx @@ -3,6 +3,7 @@ import FloatButton from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { fireEvent, render, waitFakeTimer } from '../../../tests/utils'; +import getOffset from '../util'; describe('FloatButton', () => { mountTest(FloatButton); @@ -62,4 +63,11 @@ describe('FloatButton', () => { jest.clearAllTimers(); jest.useRealTimers(); }); + + it('getOffset should return 0 when radius is 0', () => { + const result1 = getOffset(0); + expect(result1).toBe(0); + const result2 = getOffset(1); + expect(result2).not.toBe(0); + }); }); diff --git a/components/float-button/demo/badge-debug.md b/components/float-button/demo/badge-debug.md new file mode 100644 index 0000000000..19b791b5b7 --- /dev/null +++ b/components/float-button/demo/badge-debug.md @@ -0,0 +1,7 @@ +## zh-CN + +调试使用。 + +## en-US + +debug use. diff --git a/components/float-button/demo/badge-debug.tsx b/components/float-button/demo/badge-debug.tsx new file mode 100644 index 0000000000..8b17aa56c4 --- /dev/null +++ b/components/float-button/demo/badge-debug.tsx @@ -0,0 +1,22 @@ +import { ConfigProvider, FloatButton, Slider } from 'antd'; +import type { AliasToken } from 'antd/es/theme/interface'; +import React, { useState } from 'react'; + +const App: React.FC = () => { + const [radius, setRadius] = useState(0); + + const token: Partial = { + borderRadius: radius, + }; + + return ( + <> + + + + + + ); +}; + +export default App; diff --git a/components/float-button/demo/badge.md b/components/float-button/demo/badge.md new file mode 100644 index 0000000000..12fc6e911f --- /dev/null +++ b/components/float-button/demo/badge.md @@ -0,0 +1,7 @@ +## zh-CN + +右上角附带圆形徽标数字的悬浮按钮。 + +## en-US + +FloatButton with Badge. diff --git a/components/float-button/demo/badge.tsx b/components/float-button/demo/badge.tsx new file mode 100644 index 0000000000..63437d2746 --- /dev/null +++ b/components/float-button/demo/badge.tsx @@ -0,0 +1,20 @@ +import { QuestionCircleOutlined } from '@ant-design/icons'; +import { FloatButton } from 'antd'; +import React from 'react'; + +const App: React.FC = () => ( + <> + + + custom badge color} badge={{ count: 5, color: 'blue' }} /> + + + + } /> + + + + +); + +export default App; diff --git a/components/float-button/demo/render-panel.tsx b/components/float-button/demo/render-panel.tsx index 80002ebabe..84edf89ff8 100644 --- a/components/float-button/demo/render-panel.tsx +++ b/components/float-button/demo/render-panel.tsx @@ -1,11 +1,11 @@ -import React from 'react'; import { CustomerServiceOutlined, QuestionCircleOutlined, SyncOutlined } from '@ant-design/icons'; import { FloatButton } from 'antd'; +import React from 'react'; /** Test usage. Do not use in your production. */ const { _InternalPanelDoNotUseOrYouWillBeFired: InternalFloatButton } = FloatButton; -export default () => ( +const App: React.FC = () => (
} /> @@ -18,32 +18,22 @@ export default () => ( , - }, - { - icon: , - }, - { - icon: , - }, + { icon: }, + { icon: }, + { icon: }, ]} /> } trigger="click" - open items={[ - { - icon: , - }, - { - icon: , - }, - { - icon: , - }, + { icon: }, + { icon: }, + { icon: }, ]} />
); + +export default App; diff --git a/components/float-button/index.en-US.md b/components/float-button/index.en-US.md index e0a1cf8ca5..e54ec81b3b 100644 --- a/components/float-button/index.en-US.md +++ b/components/float-button/index.en-US.md @@ -26,6 +26,8 @@ FloatButton. Available since `5.0.0`. FloatButton Group Menu mode BackTop +badge +debug dot \_InternalPanelDoNotUseOrYouWillBeFired ## API @@ -44,6 +46,7 @@ FloatButton. Available since `5.0.0`. | onClick | Set the handler to handle `click` event | (event) => void | - | | | href | The target of hyperlink | string | - | | | target | Specifies where to display the linked URL | string | - | | +| badge | float-button with round logo number | refer [badge](/components/badge#api) | - | 5.4.0 | ### FloatButton.Group diff --git a/components/float-button/index.zh-CN.md b/components/float-button/index.zh-CN.md index 6ffe8d6c34..8b9100eb1b 100644 --- a/components/float-button/index.zh-CN.md +++ b/components/float-button/index.zh-CN.md @@ -27,6 +27,8 @@ demo: 浮动按钮组 菜单模式 回到顶部 +徽标数 +调试小圆点使用 \_InternalPanelDoNotUseOrYouWillBeFired ## API @@ -45,6 +47,7 @@ demo: | onClick | 点击按钮时的回调 | (event) => void | - | | | href | 点击跳转的地址,指定此属性 button 的行为和 a 链接一致 | string | - | | | target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | | +| badge | 带圆形徽标数字的悬浮按钮 | 参考[badge](/components/badge-cn#api) | - | 5.4.0 | ### FloatButton.Group diff --git a/components/float-button/interface.ts b/components/float-button/interface.ts index 745ba8f942..df4915c478 100644 --- a/components/float-button/interface.ts +++ b/components/float-button/interface.ts @@ -1,7 +1,8 @@ import type React from 'react'; -import type Group from './FloatButtonGroup'; -import type BackTop from './BackTop'; +import type { BadgeProps } from '../badge'; import type { TooltipProps } from '../tooltip'; +import type BackTop from './BackTop'; +import type Group from './FloatButtonGroup'; import type PurePanel from './PurePanel'; export type FloatButtonType = 'default' | 'primary'; @@ -10,6 +11,11 @@ export type FloatButtonShape = 'circle' | 'square'; export type FloatButtonGroupTrigger = 'click' | 'hover'; +export type FloatButtonBadgeProps = Omit< + BadgeProps, + 'status' | 'text' | 'size' | 'title' | 'children' +>; + export interface FloatButtonProps { prefixCls?: string; className?: string; @@ -22,6 +28,7 @@ export interface FloatButtonProps { tooltip?: TooltipProps['title']; href?: string; target?: React.HTMLAttributeAnchorTarget; + badge?: FloatButtonBadgeProps; onClick?: React.MouseEventHandler; } diff --git a/components/float-button/style/index.ts b/components/float-button/style/index.ts index ab888ded02..a0c031f599 100644 --- a/components/float-button/style/index.ts +++ b/components/float-button/style/index.ts @@ -1,10 +1,11 @@ import type { CSSObject } from '@ant-design/cssinjs'; import { Keyframes } from '@ant-design/cssinjs'; -import type { FullToken, GenerateStyle } from '../../theme/internal'; -import { genComponentStyleHook, mergeToken } from '../../theme/internal'; -import { initFadeMotion } from '../../style/motion/fade'; import { resetComponent } from '../../style'; +import { initFadeMotion } from '../../style/motion/fade'; import { initMotion } from '../../style/motion/motion'; +import type { FullToken, GenerateStyle } from '../../theme/internal'; +import { genComponentStyleHook, mergeToken } from '../../theme/internal'; +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; @@ -33,20 +39,19 @@ const initFloatButtonGroupMotion = (token: FloatButtonToken) => { transformOrigin: '0 0', opacity: 0, }, - '100%': { transform: 'translate3d(0, 0, 0)', transformOrigin: '0 0', opacity: 1, }, }); + const moveDownOut = new Keyframes('antFloatButtonMoveDownOut', { '0%': { transform: 'translate3d(0, 0, 0)', transformOrigin: '0 0', opacity: 1, }, - '100%': { transform: `translate3d(0, ${floatButtonSize}px, 0)`, transformOrigin: '0 0', @@ -69,7 +74,6 @@ const initFloatButtonGroupMotion = (token: FloatButtonToken) => { opacity: 0, animationTimingFunction: motionEaseInOutCirc, }, - [`&${groupPrefixCls}-wrap-leave`]: { animationTimingFunction: motionEaseInOutCirc, }, @@ -80,7 +84,16 @@ const initFloatButtonGroupMotion = (token: FloatButtonToken) => { // ============================== Group ============================== const floatButtonGroupStyle: GenerateStyle = (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 +129,7 @@ const floatButtonGroupStyle: GenerateStyle = (token [`${componentCls}-body`]: { width: floatButtonSize, height: floatButtonSize, + borderRadius: '50%', }, }, }, @@ -134,17 +148,22 @@ const floatButtonGroupStyle: GenerateStyle = (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,13 +176,12 @@ const floatButtonGroupStyle: GenerateStyle = (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, }, }, }, }, - [`${groupPrefixCls}-circle-shadow`]: { boxShadow: 'none', }, @@ -171,10 +189,11 @@ const floatButtonGroupStyle: GenerateStyle = (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 +202,23 @@ const floatButtonGroupStyle: GenerateStyle = (token // ============================== Shared ============================== const sharedFloatButtonStyle: GenerateStyle = (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', @@ -200,17 +228,24 @@ const sharedFloatButtonStyle: GenerateStyle = (toke insetInlineEnd: token.floatButtonInsetInlineEnd, insetBlockEnd: token.floatButtonInsetBlockEnd, boxShadow: token.boxShadowSecondary, - // Pure Panel '&-pure': { position: 'relative', inset: 'auto', }, - '&: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 +261,7 @@ const sharedFloatButtonStyle: GenerateStyle = (toke flexDirection: 'column', justifyContent: 'center', alignItems: 'center', - padding: `2px 4px`, + padding: `${floatButtonBodyPadding / 2}px ${floatButtonBodyPadding}px`, [`${componentCls}-icon`]: { textAlign: 'center', margin: 'auto', @@ -237,12 +272,19 @@ const sharedFloatButtonStyle: GenerateStyle = (toke }, }, }, + [`${componentCls}-rtl`]: { direction: 'rtl', }, [`${componentCls}-circle`]: { height: floatButtonSize, borderRadius: '50%', + [`${antCls}-badge`]: { + [`${antCls}-badge-dot`]: { + top: dotOffsetInCircle, + insetInlineEnd: dotOffsetInCircle, + }, + }, [`${componentCls}-body`]: { borderRadius: '50%', }, @@ -251,9 +293,15 @@ const sharedFloatButtonStyle: GenerateStyle = (toke 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`]: { @@ -315,7 +363,10 @@ export default genComponentStyleHook<'FloatButton'>('FloatButton', (token) => { fontSize, fontSizeIcon, controlItemBgHover, + paddingXXS, + borderRadiusLG, } = token; + const floatButtonToken = mergeToken(token, { floatButtonBackgroundColor: colorBgElevated, floatButtonColor: colorTextLightSolid, @@ -323,10 +374,16 @@ export default genComponentStyleHook<'FloatButton'>('FloatButton', (token) => { floatButtonFontSize: fontSize, floatButtonIconSize: fontSizeIcon * 1.5, floatButtonSize: controlHeightLG, - 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), sharedFloatButtonStyle(floatButtonToken), diff --git a/components/float-button/util.ts b/components/float-button/util.ts new file mode 100644 index 0000000000..1cee7c3afd --- /dev/null +++ b/components/float-button/util.ts @@ -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;