♿️(frontend) add focus restore store
Create Zustand store to track last focused element and restore focus after overlay close. DropdownMenu auto-stores trigger ref when an option is clicked.
This commit is contained in:
@@ -9,6 +9,7 @@ import { Button, Popover } from 'react-aria-components';
|
||||
import styled, { css } from 'styled-components';
|
||||
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { useFocusStore } from '@/stores';
|
||||
|
||||
import { BoxProps } from './Box';
|
||||
|
||||
@@ -70,8 +71,9 @@ export const DropButton = ({
|
||||
const { themeTokens } = useCunninghamTheme();
|
||||
const font = themeTokens['font']?.['families']['base'];
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(isOpen);
|
||||
const addLastFocus = useFocusStore((state) => state.addLastFocus);
|
||||
|
||||
const triggerRef = useRef(null);
|
||||
const triggerRef = useRef<HTMLButtonElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLocalOpen(isOpen);
|
||||
@@ -86,7 +88,10 @@ export const DropButton = ({
|
||||
<>
|
||||
<StyledButton
|
||||
ref={triggerRef}
|
||||
onPress={() => onOpenChangeHandler(true)}
|
||||
onPress={() => {
|
||||
addLastFocus(triggerRef.current);
|
||||
onOpenChangeHandler(true);
|
||||
}}
|
||||
aria-label={label}
|
||||
data-testid={testId}
|
||||
$css={css`
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from './useBroadcastStore';
|
||||
export * from './useFocusStore';
|
||||
export * from './useResponsiveStore';
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface UseFocusStore {
|
||||
lastFocusedElement: HTMLElement | null;
|
||||
addLastFocus: (target: HTMLElement | null) => void;
|
||||
restoreFocus: () => void;
|
||||
}
|
||||
|
||||
export const useFocusStore = create<UseFocusStore>((set, get) => ({
|
||||
lastFocusedElement: null,
|
||||
addLastFocus: (target) => set({ lastFocusedElement: target }),
|
||||
restoreFocus: () => {
|
||||
const { lastFocusedElement } = get();
|
||||
if (!lastFocusedElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
lastFocusedElement.focus();
|
||||
});
|
||||
set({ lastFocusedElement: null });
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user