Skip to content

Commit c612ae1

Browse files
authored
Merge pull request #86 from DesignSystemLab/fix/dropdown-outsideclick
Fix/dropdown outsideclick
2 parents fd72942 + ce2b69f commit c612ae1

File tree

8 files changed

+29
-15
lines changed

8 files changed

+29
-15
lines changed

packages/dropdown/src/components/Dropdown.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/** @jsxImportSource @emotion/react */
22

33
import type { DropdownProps } from '../types';
4-
import { dropdownWrapperStyle, dropdownOverlayStyle } from '../style';
5-
import { useState, useRef, useMemo, useEffect, MouseEvent, MouseEventHandler } from 'react';
4+
import { dropdownWrapperStyle } from '../style';
5+
import { useState, useRef } from 'react';
66
import { Divider } from './DropdownDivider';
77
import { Menu } from './DropdownMenu';
88
import { Trigger } from './DropdownTrigger';
@@ -12,6 +12,7 @@ import { SubMenuItem } from './DropdownSubMenuItem';
1212
import { DropdownContext } from '../context';
1313
import { useOutsideClick } from '@jdesignlab/react-utils';
1414
import { useToggleOpen } from '../hooks/useToggleOpen';
15+
import { DROPDOWN_ROLE_QUERY, DROPDOWN_MENU_OPEN_CLASS_NAME } from '../constants';
1516

1617
export const Dropdown = (props: DropdownProps) => {
1718
const dropdownRef = useRef<HTMLDivElement>(null);
@@ -32,9 +33,9 @@ export const Dropdown = (props: DropdownProps) => {
3233
ref: dropdownRef,
3334
handler: () => {
3435
const dropdownMenu = dropdownRef.current
35-
? (dropdownRef.current.querySelector("[role='menu']") as HTMLElement)
36+
? (dropdownRef.current.querySelector(DROPDOWN_ROLE_QUERY) as HTMLElement)
3637
: null;
37-
if (dropdownMenu) {
38+
if (dropdownMenu && dropdownMenu.classList.contains(DROPDOWN_MENU_OPEN_CLASS_NAME)) {
3839
useToggleOpen(dropdownMenu);
3940
}
4041
}
@@ -47,6 +48,7 @@ export const Dropdown = (props: DropdownProps) => {
4748
</DropdownContext.Provider>
4849
);
4950
};
51+
5052
Dropdown.displayName = 'Dropdown';
5153

5254
Dropdown.Trigger = Trigger;

packages/dropdown/src/components/DropdownMenuItem.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { dropdownItemStyle } from '../style';
55
import type { DropdownMenuItemProps } from '../types';
66
import { useKeyboardHandler } from '../hooks/useKeyboardHandler';
77
import { useSelectItem } from '../hooks/useSelectItem';
8+
import { NOT_DISABLED_DROPDOWN_MENU_QUERY } from '../constants';
89

910
export const MenuItem = (props: DropdownMenuItemProps) => {
1011
const menuItemRef = useRef<HTMLLIElement>(null);
@@ -26,7 +27,7 @@ export const MenuItem = (props: DropdownMenuItemProps) => {
2627
useKeyboardHandler({
2728
event,
2829
parentScope: '.menu',
29-
selectorOfList: '.menu_item:not([disabled])',
30+
selectorOfList: NOT_DISABLED_DROPDOWN_MENU_QUERY,
3031
setState: setSubOpen,
3132
onClick
3233
});

packages/dropdown/src/components/DropdownSubMenuItem.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { dropdownItemStyle } from '../style';
44
import type { DropdownSubMenuItemProps } from '../types';
55
import { useKeyboardHandler } from '../hooks/useKeyboardHandler';
66
import { useSelectItem } from '../hooks/useSelectItem';
7+
import { DROPDOWN_MENU_OPEN_CLASS_NAME, NOT_DISABLED_DROPDOWN_SUB_ITEM_QUERY } from '../constants';
78

89
export const SubMenuItem = (props: DropdownSubMenuItemProps) => {
910
const menuItemRef = useRef<HTMLLIElement>(null);
@@ -15,8 +16,8 @@ export const SubMenuItem = (props: DropdownSubMenuItemProps) => {
1516

1617
useKeyboardHandler({
1718
event,
18-
parentScope: '.menu_item',
19-
selectorOfList: '.sub_item:not([disabled])'
19+
parentScope: DROPDOWN_MENU_OPEN_CLASS_NAME,
20+
selectorOfList: NOT_DISABLED_DROPDOWN_SUB_ITEM_QUERY
2021
});
2122
};
2223

packages/dropdown/src/components/DropdownTrigger.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DropdownContext } from '../context';
33
import type { DropdownTriggerProps } from '../types';
44
import useOpenKeyDown from '../hooks/useOpenKeyDown';
55
import { useToggleOpen } from '../hooks/useToggleOpen';
6+
import { DROPDOWN_ROLE_QUERY, DROPDOWN_MENU_WRAPPER_CLASS } from '../constants';
67

78
export const Trigger = (props: DropdownTriggerProps) => {
89
const { children, ...otherProps } = props;
@@ -19,7 +20,9 @@ export const Trigger = (props: DropdownTriggerProps) => {
1920

2021
const onClickHandle = () => {
2122
if (triggerRef?.current) {
22-
const dropdownMenu = triggerRef.current.closest('.menu_wrapper')?.querySelector('[role="menu"]') as HTMLElement;
23+
const dropdownMenu = triggerRef.current
24+
.closest(DROPDOWN_MENU_WRAPPER_CLASS)
25+
?.querySelector(DROPDOWN_ROLE_QUERY) as HTMLElement;
2326
useToggleOpen(dropdownMenu);
2427
}
2528
};

packages/dropdown/src/constants.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/** DOM */
2+
export const DROPDOWN_ROLE_QUERY = "[role='menu']";
3+
export const NOT_DISABLED_DROPDOWN_MENU_QUERY = '.menu_item:not([disabled])';
4+
export const NOT_DISABLED_DROPDOWN_SUB_ITEM_QUERY = '.menu_item:not([disabled])';
5+
export const DROPDOWN_MENU_WRAPPER_CLASS = '.menu_wrapper';
6+
export const DROPDOWN_MENU_OPEN_CLASS_NAME = 'menu_open';

packages/dropdown/src/types/base.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type DropdownAnchor = 'top' | 'right' | 'bottom' | 'left';

packages/dropdown/src/types/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './base';
2+
export * from './props';

packages/dropdown/src/types.ts renamed to packages/dropdown/src/types/props.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import type { ColorToken } from '@jdesignlab/theme';
2-
3-
export type DropdownAnchor = 'top' | 'right' | 'bottom' | 'left';
1+
import { DropdownAnchor } from './base';
42

53
export interface DropdownProps {
64
children?: React.ReactNode;
@@ -13,6 +11,10 @@ export interface DropdownTriggerProps {
1311
children?: React.ReactNode;
1412
}
1513

14+
export interface DropdownSubMenuProps {
15+
children?: React.ReactNode;
16+
}
17+
1618
export interface DropdownMenuProps {
1719
children?: React.ReactNode;
1820
}
@@ -24,10 +26,6 @@ export interface DropdownMenuItemProps {
2426
hasSub?: boolean;
2527
}
2628

27-
export interface DropdownSubMenuProps {
28-
children?: React.ReactNode;
29-
}
30-
3129
export interface DropdownSubMenuItemProps {
3230
children?: React.ReactNode;
3331
disabled?: boolean;

0 commit comments

Comments
 (0)