Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions src/components/context-menu/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,13 @@ class ContextMenu extends React.Component<ContextMenuProps, ContextMenuState> {

focusTarget = () => {
// breaks encapsulation but the only alternative is passing a ref to an unknown child component
const menuTargetEl = document.getElementById(this.menuTargetID);
if (menuTargetEl) {
menuTargetEl.focus();
const wrapperEl = document.getElementById(this.menuTargetID);
if (wrapperEl) {
// The ID is now on the wrapper div, so we need to focus the first child element
const targetEl = wrapperEl.firstElementChild as HTMLElement;
if (targetEl && targetEl.focus) {
targetEl.focus();
}
}
};

Expand Down Expand Up @@ -146,13 +150,11 @@ class ContextMenu extends React.Component<ContextMenuProps, ContextMenuState> {
const menu = elements[1];

const menuTargetProps = {
id: this.menuTargetID,
key: this.menuTargetID,
onContextMenu: this.handleContextMenu,
};

const menuProps = {
id: this.menuID,
key: this.menuID,
initialFocusIndex: null,
onClose: this.handleMenuClose,
Expand All @@ -172,12 +174,16 @@ class ContextMenu extends React.Component<ContextMenuProps, ContextMenuState> {
{...tetherProps}
renderTarget={ref => {
return React.isValidElement(menuTarget) ? (
<div ref={ref}>{React.cloneElement(menuTarget, menuTargetProps)}</div>
<div ref={ref} id={this.menuTargetID}>
{React.cloneElement(menuTarget, menuTargetProps)}
</div>
) : null;
}}
renderElement={ref => {
return isOpen && React.isValidElement(menu) ? (
<div ref={ref}>{React.cloneElement(menu, menuProps)}</div>
<div ref={ref} id={this.menuID}>
{React.cloneElement(menu, menuProps)}
</div>
) : null;
}}
/>
Expand Down
13 changes: 9 additions & 4 deletions src/components/context-menu/__tests__/ContextMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ describe('components/context-menu/ContextMenu', () => {
const button = wrapper.find(FakeButton);
expect(button.length).toBe(1);

expect(button.prop('id')).toEqual(instance.menuTargetID);
expect(button.key()).toEqual(instance.menuTargetID);

const wrapperDiv = wrapper.find(`#${instance.menuTargetID}`);
expect(wrapperDiv.length).toBe(1);
});

test('should not render child menu when menu is closed', () => {
Expand Down Expand Up @@ -98,9 +100,11 @@ describe('components/context-menu/ContextMenu', () => {
const menu = wrapper.find(FakeMenu);
expect(menu.length).toBe(1);

expect(menu.prop('id')).toEqual(instance.menuID);
expect(menu.key()).toEqual(instance.menuID);
expect(menu.prop('initialFocusIndex')).toEqual(null);

const wrapperDiv = wrapper.find(`#${instance.menuID}`);
expect(wrapperDiv.length).toBe(1);
});

test('should render TetherComponent with correct props with correct default values', () => {
Expand Down Expand Up @@ -463,8 +467,9 @@ describe('components/context-menu/ContextMenu', () => {
</ContextMenu>,
);
const instance = wrapper.instance() as ContextMenu;
const menuTargetEl = document.getElementById(instance.menuTargetID) as HTMLButtonElement;
menuTargetEl.focus = onFocusTargetSpy;
const wrapperEl = document.getElementById(instance.menuTargetID) as HTMLDivElement;
const targetEl = wrapperEl.firstElementChild as HTMLButtonElement;
targetEl.focus = onFocusTargetSpy;
instance.focusTarget();
expect(onFocusTargetSpy).toHaveBeenCalled();
});
Expand Down