| import React from 'react'; |
| import FileTextOutlined from '@ant-design/icons/FileTextOutlined'; |
| import { omit } from '@rc-component/util'; |
| import { clsx } from 'clsx'; |
|
|
| import convertToTooltipProps from '../_util/convertToTooltipProps'; |
| import { useMergeSemantic, useZIndex } from '../_util/hooks'; |
| import type { SemanticClassNamesType, SemanticStylesType } from '../_util/hooks'; |
| import { devUseWarning } from '../_util/warning'; |
| import Badge from '../badge'; |
| import type { BadgeProps } from '../badge'; |
| import Button from '../button/Button'; |
| import type { |
| ButtonSemanticClassNames, |
| ButtonSemanticName, |
| ButtonSemanticStyles, |
| } from '../button/Button'; |
| import type { ButtonHTMLType } from '../button/buttonHelpers'; |
| import { ConfigContext } from '../config-provider'; |
| import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; |
| import Tooltip from '../tooltip'; |
| import type { TooltipProps } from '../tooltip'; |
| import type BackTop from './BackTop'; |
| import { GroupContext } from './context'; |
| import type FloatButtonGroup from './FloatButtonGroup'; |
| import type PurePanel from './PurePanel'; |
| import useStyle from './style'; |
|
|
| export type FloatButtonElement = HTMLAnchorElement & HTMLButtonElement; |
|
|
| export interface FloatButtonRef { |
| nativeElement: FloatButtonElement | null; |
| } |
|
|
| export type FloatButtonType = 'default' | 'primary'; |
|
|
| export type FloatButtonShape = 'circle' | 'square'; |
|
|
| export type FloatButtonGroupTrigger = 'click' | 'hover'; |
|
|
| export type FloatButtonBadgeProps = Omit<BadgeProps, 'status' | 'text' | 'title' | 'children'>; |
|
|
| export type FloatButtonSemanticName = ButtonSemanticName; |
|
|
| export type FloatButtonClassNamesType = SemanticClassNamesType< |
| FloatButtonProps, |
| ButtonSemanticClassNames |
| >; |
|
|
| export type FloatButtonStylesType = SemanticStylesType<FloatButtonProps, ButtonSemanticStyles>; |
|
|
| export interface FloatButtonProps extends React.DOMAttributes<FloatButtonElement> { |
| |
| prefixCls?: string; |
| className?: string; |
| rootClassName?: string; |
| style?: React.CSSProperties; |
| classNames?: FloatButtonClassNamesType; |
| styles?: FloatButtonStylesType; |
|
|
| |
| icon?: React.ReactNode; |
| |
| description?: React.ReactNode; |
| content?: React.ReactNode; |
| type?: FloatButtonType; |
| shape?: FloatButtonShape; |
| tooltip?: React.ReactNode | TooltipProps; |
| href?: string; |
| target?: React.HTMLAttributeAnchorTarget; |
| badge?: FloatButtonBadgeProps; |
| |
| |
| |
| |
| htmlType?: ButtonHTMLType; |
| 'aria-label'?: React.HtmlHTMLAttributes<HTMLElement>['aria-label']; |
| } |
|
|
| export const floatButtonPrefixCls = 'float-btn'; |
|
|
| const InternalFloatButton = React.forwardRef<FloatButtonElement, FloatButtonProps>((props, ref) => { |
| const { |
| prefixCls: customizePrefixCls, |
| className, |
| rootClassName, |
| style, |
| type = 'default', |
| shape = 'circle', |
| icon, |
| description, |
| content, |
| tooltip, |
| badge = {}, |
| classNames, |
| styles, |
| ...restProps |
| } = props; |
| const { getPrefixCls, direction } = React.useContext(ConfigContext); |
| const groupContext = React.useContext(GroupContext); |
| const prefixCls = getPrefixCls(floatButtonPrefixCls, customizePrefixCls); |
| const rootCls = useCSSVarCls(prefixCls); |
|
|
| const { |
| shape: contextShape, |
| individual: contextIndividual, |
| classNames: contextClassNames, |
| styles: contextStyles, |
| } = groupContext || {}; |
|
|
| const mergedShape = contextShape || shape; |
| const mergedIndividual = contextIndividual ?? true; |
|
|
| const mergedContent = content ?? description; |
|
|
| |
| const mergedProps: FloatButtonProps = { |
| ...props, |
| type, |
| shape: mergedShape, |
| }; |
|
|
| |
| const [hashId, cssVarCls] = useStyle(prefixCls, rootCls); |
|
|
| const floatButtonClassNames = React.useMemo<FloatButtonProps['classNames']>( |
| () => ({ icon: `${prefixCls}-icon`, content: `${prefixCls}-content` }), |
| [prefixCls], |
| ); |
|
|
| const [mergedClassNames, mergedStyles] = useMergeSemantic< |
| FloatButtonClassNamesType, |
| FloatButtonStylesType, |
| FloatButtonProps |
| >([floatButtonClassNames, contextClassNames, classNames], [contextStyles, styles], { |
| props: mergedProps, |
| }); |
|
|
| |
| const mergedIcon = !mergedContent && !icon ? <FileTextOutlined /> : icon; |
|
|
| |
|
|
| const [zIndex] = useZIndex('FloatButton', style?.zIndex as number); |
|
|
| const mergedStyle: React.CSSProperties = { ...style, zIndex }; |
|
|
| |
| |
| const badgeProps = omit(badge, ['title', 'children', 'status', 'text'] as any[]) as typeof badge; |
|
|
| const badgeNode = 'badge' in props && ( |
| <Badge |
| {...badgeProps} |
| className={clsx(badgeProps.className, `${prefixCls}-badge`, { |
| [`${prefixCls}-badge-dot`]: badgeProps.dot, |
| })} |
| /> |
| ); |
|
|
| |
| const tooltipProps = convertToTooltipProps(tooltip); |
|
|
| |
| if (process.env.NODE_ENV !== 'production') { |
| const warning = devUseWarning('FloatButton'); |
|
|
| warning( |
| !(mergedShape === 'circle' && mergedContent), |
| 'usage', |
| 'supported only when `shape` is `square`. Due to narrow space for text, short sentence is recommended.', |
| ); |
|
|
| warning.deprecated(!description, 'description', 'content'); |
| } |
|
|
| |
| let node = ( |
| <Button |
| {...restProps} |
| ref={ref} |
| // Styles |
| className={clsx( |
| hashId, |
| cssVarCls, |
| rootCls, |
| prefixCls, |
| className, |
| rootClassName, |
| `${prefixCls}-${type}`, |
| `${prefixCls}-${mergedShape}`, |
| { |
| [`${prefixCls}-rtl`]: direction === 'rtl', |
| [`${prefixCls}-individual`]: mergedIndividual, |
| [`${prefixCls}-icon-only`]: !mergedContent, |
| }, |
| )} |
| classNames={mergedClassNames} |
| styles={mergedStyles} |
| style={mergedStyle} |
| shape={mergedShape} |
| // Others |
| type={type} |
| size="large" |
| icon={mergedIcon} |
| _skipSemantic |
| > |
| {mergedContent} |
| {badgeNode} |
| </Button> |
| ); |
|
|
| if (tooltipProps) { |
| node = <Tooltip {...tooltipProps}>{node}</Tooltip>; |
| } |
|
|
| return node; |
| }); |
|
|
| type CompoundedComponent = typeof InternalFloatButton & { |
| Group: typeof FloatButtonGroup; |
| BackTop: typeof BackTop; |
| _InternalPanelDoNotUseOrYouWillBeFired: typeof PurePanel; |
| }; |
|
|
| const FloatButton = InternalFloatButton as CompoundedComponent; |
|
|
| if (process.env.NODE_ENV !== 'production') { |
| FloatButton.displayName = 'FloatButton'; |
| } |
|
|
| export default FloatButton; |
|
|