Skip to content

Commit 59f0c5d

Browse files
committed
fix ContextualHelpTrigger dialog offset and hover behavior when entered via a open submenu
this unfortunately breaks another interaction case but to handle later
1 parent f9bf3af commit 59f0c5d

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
lines changed

packages/@react-aria/menu/src/useSubMenuTrigger.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {AriaMenuItemProps} from './useMenuItem';
1515
import {AriaMenuOptions} from './useMenu';
1616
import type {AriaPopoverProps} from '@react-aria/overlays';
1717
import {FocusableElement, FocusStrategy, PressEvent, Node as RSNode} from '@react-types/shared';
18-
import {isElementInChildOfActiveScope} from '@react-aria/focus';
1918
import {RefObject, useCallback, useRef} from 'react';
2019
import type {SubMenuTriggerState} from '@react-stately/menu';
2120
import {useEffectEvent, useId, useLayoutEffect} from '@react-aria/utils';
@@ -180,7 +179,10 @@ export function useSubMenuTrigger<T>(props: AriaSubMenuTriggerProps, state: SubM
180179
};
181180

182181
let onBlur = (e) => {
183-
if (state.isOpen && (!isElementInChildOfActiveScope(e.relatedTarget) || parentMenuRef.current.contains(e.relatedTarget))) {
182+
// TODO: getting rid of the (!isElementInChildOfActiveScope(e.relatedTarget) part of the check below fixes hovering to open a root unavailable menu item when focus is on a submenu
183+
// but breaks the case where the user is hovering over a submenu's submenu trigger child item and then hovers a root menu item (eg hover lvl 1 item 2 -> hover lvl 2 item 3 -> hover lvl 1 item 3)
184+
// Ideally we'd be able to track the full menu tree and then check if focus has moved to an element that isn't part of the current submenu tree and close it then
185+
if (state.isOpen && parentMenuRef.current.contains(e.relatedTarget)) {
184186
onSubMenuClose();
185187
}
186188
};

packages/@react-spectrum/menu/src/ContextualHelpTrigger.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ function ContextualHelpTrigger<T>(props: MenuDialogTriggerProps<T>): ReactElemen
8686
ref={popoverRef}
8787
triggerRef={triggerRef}
8888
placement="end top"
89+
containerPadding={0}
90+
crossOffset={-5}
8991
offset={-10}
9092
hideArrow
9193
enableBothDismissButtons>

packages/@react-spectrum/menu/stories/SubMenu.stories.tsx

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ import AlignCenter from '@spectrum-icons/workflow/AlignCenter';
1515
import AlignLeft from '@spectrum-icons/workflow/AlignLeft';
1616
import AlignRight from '@spectrum-icons/workflow/AlignRight';
1717
import AnnotatePen from '@spectrum-icons/workflow/AnnotatePen';
18+
import {Content} from '@react-spectrum/view';
19+
import {ContextualHelpTrigger, Item, Menu, Section, SubMenuTrigger} from '../';
1820
import defaultConfig, {render as renderMenuTrigger} from './MenuTrigger.stories';
19-
import {Item, Menu, Section, SubMenuTrigger} from '../';
20-
import {Keyboard, Text} from '@react-spectrum/text';
21+
import {Dialog} from '@react-spectrum/dialog';
22+
import {Heading, Keyboard, Text} from '@react-spectrum/text';
2123
import React from 'react';
2224
import TextIndentIncrease from '@spectrum-icons/workflow/TextIndentIncrease';
2325
import TextItalics from '@spectrum-icons/workflow/TextItalic';
@@ -388,6 +390,53 @@ export const Complex = {
388390
name: 'complex'
389391
};
390392

393+
export const UnavailableWithSubMenu = {
394+
render: (args) => (
395+
renderMenuTrigger(
396+
<Menu onAction={action('lvl 1 menu onAction')} {...args}>
397+
<Item key="Lvl 1 Item 1">Lvl 1 Item 1</Item>
398+
<SubMenuTrigger>
399+
<Item key="Lvl 1 Item 2">Lvl 1 Item 2</Item>
400+
<Menu onAction={action('lvl 2.2 menu onAction')} {...args.subMenu1Props}>
401+
<ContextualHelpTrigger isUnavailable>
402+
<Item key="Lvl 2 Item 1">Lvl 2.2 Item 1</Item>
403+
<Dialog>
404+
<Heading>another one</Heading>
405+
<Content>try hovering on other items</Content>
406+
</Dialog>
407+
</ContextualHelpTrigger>
408+
<Item key="Lvl 2 Item 2">Lvl 2.2 Item 2</Item>
409+
<SubMenuTrigger>
410+
<Item key="Lvl 2 Item 3">Lvl 2.2 Item 3</Item>
411+
<Menu onAction={action('lvl 3 menu onAction')} {...args.subMenu2Props}>
412+
<Item key="Lvl 3 Item 1">Lvl 3 Item 1</Item>
413+
<Item key="Lvl 3 Item 2">Lvl 3 Item 2</Item>
414+
<Item key="Lvl 3 Item 3">Lvl 3 Item 3</Item>
415+
</Menu>
416+
</SubMenuTrigger>
417+
</Menu>
418+
</SubMenuTrigger>
419+
<ContextualHelpTrigger isUnavailable>
420+
<Item key="Lvl 1 Item 3">Lvl 1 Item 3</Item>
421+
<Dialog>
422+
<Heading>hello</Heading>
423+
<Content>Is it me you're looking for?</Content>
424+
</Dialog>
425+
</ContextualHelpTrigger>
426+
<SubMenuTrigger>
427+
<Item key="Lvl 1 Item 4">Lvl 1 Item 4</Item>
428+
<Menu onAction={action('lvl 2.4 menu onAction')} {...args.subMenu1Props}>
429+
<Item key="Lvl 2.4 Item 1">Lvl 2.4 Item 1</Item>
430+
<Item key="Lvl 2.4 Item 2">Lvl 2.4 Item 2</Item>
431+
<Item key="Lvl 2.4 Item 3">Lvl 2.4 Item 3</Item>
432+
</Menu>
433+
</SubMenuTrigger>
434+
</Menu>
435+
)
436+
),
437+
name: 'with unavailable menu item'
438+
};
439+
391440
export const SubMenuActions = {
392441
render: (args) => renderMenuTrigger(
393442
<Menu onAction={action('onAction lvl 1 menu')} onClose={action('onClose lvl 1 menu')} {...args}>

0 commit comments

Comments
 (0)