diff --git a/components/button/__tests__/index.test.tsx b/components/button/__tests__/index.test.tsx index 56e6a6b1a9..f5ae30c8c5 100644 --- a/components/button/__tests__/index.test.tsx +++ b/components/button/__tests__/index.test.tsx @@ -474,4 +474,10 @@ describe('Button', () => { '--ant-button-solid-text-color': '#000', }); }); + + it('autoFocus should work', () => { + const { container } = render(); + + expect(container.querySelector('button')).toBe(document.activeElement); + }); }); diff --git a/components/button/button.tsx b/components/button/button.tsx index 9abc657f41..aa98000d2d 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -1,7 +1,7 @@ -import React, { Children, createRef, useContext, useEffect, useMemo, useState } from 'react'; +import React, { Children, useContext, useEffect, useMemo, useRef, useState } from 'react'; import classNames from 'classnames'; import omit from 'rc-util/lib/omit'; -import { composeRef } from 'rc-util/lib/ref'; +import { useComposeRef } from 'rc-util/lib/ref'; import { devUseWarning } from '../_util/warning'; import Wave from '../_util/wave'; @@ -119,6 +119,7 @@ const InternalCompoundedButton = React.forwardRef< classNames: customClassNames, style: customStyle = {}, autoInsertSpace, + autoFocus, ...rest } = props; @@ -162,13 +163,15 @@ const InternalCompoundedButton = React.forwardRef< const [hasTwoCNChar, setHasTwoCNChar] = useState(false); - const internalRef = createRef(); + const buttonRef = useRef(); - const buttonRef = composeRef(ref, internalRef); + const mergedRef = useComposeRef(ref, buttonRef); const needInserted = Children.count(children) === 1 && !icon && !isUnBorderedButtonVariant(mergedVariant); + // ========================= Effect ========================= + // Loading useEffect(() => { let delayTimer: ReturnType | null = null; if (loadingOrDelay.delay > 0) { @@ -190,12 +193,13 @@ const InternalCompoundedButton = React.forwardRef< return cleanupTimer; }, [loadingOrDelay]); + // Two chinese characters check useEffect(() => { // FIXME: for HOC usage like - if (!buttonRef || !(buttonRef as any).current || !mergedInsertSpace) { + if (!buttonRef.current || !mergedInsertSpace) { return; } - const buttonText = (buttonRef as any).current.textContent; + const buttonText = buttonRef.current.textContent || ''; if (needInserted && isTwoCNChar(buttonText)) { if (!hasTwoCNChar) { setHasTwoCNChar(true); @@ -203,8 +207,16 @@ const InternalCompoundedButton = React.forwardRef< } else if (hasTwoCNChar) { setHasTwoCNChar(false); } - }, [buttonRef]); + }); + // Auto focus + useEffect(() => { + if (autoFocus && buttonRef.current) { + buttonRef.current.focus(); + } + }, []); + + // ========================= Events ========================= const handleClick = React.useCallback( (e: React.MouseEvent) => { // FIXME: https://github.com/ant-design/ant-design/issues/30207 @@ -217,6 +229,7 @@ const InternalCompoundedButton = React.forwardRef< [props.onClick, innerLoading, mergedDisabled], ); + // ========================== Warn ========================== if (process.env.NODE_ENV !== 'production') { const warning = devUseWarning('Button'); @@ -233,6 +246,7 @@ const InternalCompoundedButton = React.forwardRef< ); } + // ========================== Size ========================== const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction); const sizeClassNameMap = { large: 'lg', small: 'sm', middle: undefined }; @@ -245,6 +259,7 @@ const InternalCompoundedButton = React.forwardRef< const linkButtonRestProps = omit(rest as ButtonProps & { navigate: any }, ['navigate']); + // ========================= Render ========================= const classes = classNames( prefixCls, hashId, @@ -301,7 +316,7 @@ const InternalCompoundedButton = React.forwardRef< href={mergedDisabled ? undefined : linkButtonRestProps.href} style={fullStyle} onClick={handleClick} - ref={buttonRef as React.Ref} + ref={mergedRef as React.Ref} tabIndex={mergedDisabled ? -1 : 0} > {iconNode} @@ -318,7 +333,7 @@ const InternalCompoundedButton = React.forwardRef< style={fullStyle} onClick={handleClick} disabled={mergedDisabled} - ref={buttonRef as React.Ref} + ref={mergedRef as React.Ref} > {iconNode} {kids}