Skip to content

Commit

Permalink
fix(MenuList): Removing ignoreKeydown from MenuList. (#31393)
Browse files Browse the repository at this point in the history
MenuList had ignoreKeydown for Tab to prevent Tabster from handling the Tab press. As a side effect this ignoreKeydown was affecting submenus too. This PR uses TabsterMoveFocusEvent to prevent Tabster from handling the Tab press in a particular case that doesn't affect submenus.
  • Loading branch information
mshoho authored Jun 13, 2024
1 parent 974e041 commit b1f0382
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "Removing ignoreKeydown on MenuList as it has side effect on submenus.",
"packageName": "@fluentui/react-menu",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Exposing TabsterMoveFocusEvent.",
"packageName": "@fluentui/react-tabster",
"email": "[email protected]",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exports[`MenuList renders a default state 1`] = `
<div
aria-labelledby=""
className="fui-MenuList"
data-tabster="{\\"mover\\":{\\"cyclic\\":true,\\"direction\\":1,\\"memorizeCurrent\\":true},\\"focusable\\":{\\"ignoreKeydown\\":{\\"Tab\\":false}}}"
data-tabster="{\\"mover\\":{\\"cyclic\\":true,\\"direction\\":1,\\"memorizeCurrent\\":true}}"
role="menu"
>
Default MenuList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import {
getIntrinsicElementProps,
slot,
} from '@fluentui/react-utilities';
import { useArrowNavigationGroup, useFocusFinders } from '@fluentui/react-tabster';
import {
useArrowNavigationGroup,
useFocusFinders,
TabsterMoveFocusEventName,
type TabsterMoveFocusEvent,
} from '@fluentui/react-tabster';
import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
import { useHasParentContext } from '@fluentui/react-context-selector';
import { useMenuContext_unstable } from '../../contexts/menuContext';
import { MenuContext } from '../../contexts/menuContext';
Expand All @@ -17,9 +23,10 @@ import type { MenuListProps, MenuListState } from './MenuList.types';
*/
export const useMenuList_unstable = (props: MenuListProps, ref: React.Ref<HTMLElement>): MenuListState => {
const { findAllFocusable } = useFocusFinders();
const { targetDocument } = useFluent();
const menuContext = useMenuContextSelectors();
const hasMenuContext = useHasParentContext(MenuContext);
const focusAttributes = useArrowNavigationGroup({ circular: true, ignoreDefaultKeydown: { Tab: hasMenuContext } });
const focusAttributes = useArrowNavigationGroup({ circular: true });

if (usingPropsAndMenuContext(props, menuContext, hasMenuContext)) {
// TODO throw warnings in development safely
Expand All @@ -29,6 +36,27 @@ export const useMenuList_unstable = (props: MenuListProps, ref: React.Ref<HTMLEl

const innerRef = React.useRef<HTMLElement>(null);

React.useEffect(() => {
const element = innerRef.current;

if (hasMenuContext && targetDocument && element) {
const onTabsterMoveFocus = (e: TabsterMoveFocusEvent) => {
const nextElement = e.detail.next;

if (nextElement && element.contains(targetDocument.activeElement) && !element.contains(nextElement)) {
// Preventing Tabster from handling Tab press, useMenuPopover will handle it.
e.preventDefault();
}
};

targetDocument.addEventListener(TabsterMoveFocusEventName, onTabsterMoveFocus);

return () => {
targetDocument.removeEventListener(TabsterMoveFocusEventName, onTabsterMoveFocus);
};
}
}, [innerRef, targetDocument, hasMenuContext]);

const setFocusByFirstCharacter = React.useCallback(
(e: React.KeyboardEvent<HTMLElement>, itemEl: HTMLElement) => {
// TODO use some kind of children registration to reduce dependency on DOM roles
Expand Down
13 changes: 11 additions & 2 deletions packages/react-components/react-tabster/etc/react-tabster.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { MoverMoveFocusEvent } from 'tabster';
import { MoverMoveFocusEventName } from 'tabster';
import * as React_2 from 'react';
import type { RefObject } from 'react';
import { TabsterMoveFocusEvent } from 'tabster';
import { TabsterMoveFocusEventName } from 'tabster';
import { Types } from 'tabster';

// @internal (undocumented)
Expand Down Expand Up @@ -1220,8 +1222,13 @@ interface TabsterElementStorageEntry {
// @public (undocumented)
type TabsterEventWithDetails<D> = CustomEvent<D | undefined>;

export { TabsterMoveFocusEvent }

// @public (undocumented)
type TabsterMoveFocusEvent_2 = TabsterEventWithDetails<TabsterMoveFocusEventDetails>;

// @public (undocumented)
type TabsterMoveFocusEvent = TabsterEventWithDetails<TabsterMoveFocusEventDetails>;
export type TabsterMoveFocusEventDetail = EventsTypes.TabsterMoveFocusEventDetail;

// @public (undocumented)
interface TabsterMoveFocusEventDetails {
Expand All @@ -1235,6 +1242,8 @@ interface TabsterMoveFocusEventDetails {
relatedEvent?: KeyboardEvent;
}

export { TabsterMoveFocusEventName }

// @public (undocumented)
type TabsterOnElement = Partial<RootOnElement & DeloserOnElement & ModalizerOnElement & FocusableOnElement & MoverOnElement & GroupperOnElement & ObservedOnElement & OutlineOnElement & UncontrolledOnElement & SysOnElement & RestorerOnElement>;

Expand Down Expand Up @@ -1285,7 +1294,7 @@ declare namespace TabsterTypes {
GroupperMoveFocusEvent_2 as GroupperMoveFocusEvent,
TabsterEventWithDetails,
TabsterMoveFocusEventDetails,
TabsterMoveFocusEvent,
TabsterMoveFocusEvent_2 as TabsterMoveFocusEvent,
TabsterDOMAttribute_2 as TabsterDOMAttribute,
TabsterCoreProps,
DOMAPI,
Expand Down
5 changes: 5 additions & 0 deletions packages/react-components/react-tabster/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import {
GroupperMoveFocusActions,
MoverMemorizedElementEventName,
MoverMemorizedElementEvent,
TabsterMoveFocusEventName,
TabsterMoveFocusEvent,
} from 'tabster';

export type TabsterDOMAttribute = Types.TabsterDOMAttribute;
Expand Down Expand Up @@ -80,3 +82,6 @@ export type GroupperMoveFocusEventDetail = EventsTypes.GroupperMoveFocusEventDet

export { MoverMemorizedElementEventName, MoverMemorizedElementEvent };
export type MoverMemorizedElementEventDetail = EventsTypes.MoverMemorizedElementEventDetail;

export { TabsterMoveFocusEventName, TabsterMoveFocusEvent };
export type TabsterMoveFocusEventDetail = EventsTypes.TabsterMoveFocusEventDetail;

0 comments on commit b1f0382

Please sign in to comment.