From 26fd9a4a1c6a91f7dafe11b8364748a4498049e3 Mon Sep 17 00:00:00 2001 From: CatsJuice Date: Fri, 9 Aug 2024 05:50:22 +0000 Subject: [PATCH] feat(component): add autoFocusConfirmButton for confirm-modal (#7801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit close #5813
🎥 Video uploaded on Graphite:
--- .../component/src/hooks/focus-and-select.ts | 33 +++++++++++++ .../frontend/component/src/hooks/index.ts | 1 + .../component/src/ui/button/button.tsx | 19 ++++++- .../frontend/component/src/ui/input/input.tsx | 49 +++++++------------ .../component/src/ui/modal/confirm-modal.tsx | 7 +++ 5 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 packages/frontend/component/src/hooks/focus-and-select.ts create mode 100644 packages/frontend/component/src/hooks/index.ts diff --git a/packages/frontend/component/src/hooks/focus-and-select.ts b/packages/frontend/component/src/hooks/focus-and-select.ts new file mode 100644 index 0000000000..edd92c5eaa --- /dev/null +++ b/packages/frontend/component/src/hooks/focus-and-select.ts @@ -0,0 +1,33 @@ +import { useLayoutEffect, useRef } from 'react'; + +export const useAutoFocus = ( + autoFocus?: boolean +) => { + const ref = useRef(null); + + useLayoutEffect(() => { + if (ref.current && autoFocus) { + // to avoid clicking on something focusable(e.g MenuItem), + // then the input will not be focused + setTimeout(() => { + ref.current?.focus(); + }, 0); + } + }, [autoFocus]); + + return ref; +}; + +export const useAutoSelect = ( + autoSelect?: boolean +) => { + const ref = useAutoFocus(autoSelect); + + useLayoutEffect(() => { + if (ref.current && autoSelect) { + ref.current?.select(); + } + }, [autoSelect, ref]); + + return ref; +}; diff --git a/packages/frontend/component/src/hooks/index.ts b/packages/frontend/component/src/hooks/index.ts new file mode 100644 index 0000000000..2c69d81da9 --- /dev/null +++ b/packages/frontend/component/src/hooks/index.ts @@ -0,0 +1 @@ +export { useAutoFocus, useAutoSelect } from './focus-and-select'; diff --git a/packages/frontend/component/src/ui/button/button.tsx b/packages/frontend/component/src/ui/button/button.tsx index df7a55d53d..ed25560e3e 100644 --- a/packages/frontend/component/src/ui/button/button.tsx +++ b/packages/frontend/component/src/ui/button/button.tsx @@ -7,6 +7,7 @@ import type { } from 'react'; import { cloneElement, forwardRef, useCallback } from 'react'; +import { useAutoFocus } from '../../hooks'; import { Loading } from '../loading'; import { Tooltip, type TooltipProps } from '../tooltip'; import * as styles from './button.css'; @@ -120,12 +121,15 @@ export const Button = forwardRef( tooltip, tooltipShortcut, tooltipOptions, + autoFocus, onClick, ...otherProps }, - ref + upstreamRef ) => { + const ref = useAutoFocus(autoFocus); + const handleClick = useCallback( (e: MouseEvent) => { if (loading || disabled) return; @@ -134,11 +138,22 @@ export const Button = forwardRef( [disabled, loading, onClick] ); + const buttonRef = (el: HTMLButtonElement | null) => { + ref.current = el; + if (upstreamRef) { + if (typeof upstreamRef === 'function') { + upstreamRef(el); + } else { + upstreamRef.current = el; + } + } + }; + return (