@rescui/menu 0.13.8-RUI-297-Add-react-compiler-to-the-packages-build-dbbefd7b8.14 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/_virtual/check-outline.js +106 -0
- package/lib/_virtual/index.css.js +15 -0
- package/lib/index.css +191 -76
- package/lib/index.d.ts +1 -5
- package/lib/menu.d.ts +17 -11
- package/lib/menu.js +108 -24
- package/lib/menu.p.module.css.js +34 -27
- package/lib/parts/divider.d.ts +3 -6
- package/lib/parts/divider.js +1 -0
- package/lib/parts/group-header.d.ts +2 -8
- package/lib/parts/group-header.js +2 -1
- package/lib/parts/menu-context.d.ts +2 -19
- package/lib/parts/menu-context.js +7 -8
- package/lib/parts/menu-item.d.ts +25 -13
- package/lib/parts/menu-item.js +98 -34
- package/lib/parts/navigation-utils.d.ts +2 -2
- package/lib/parts/use-menu-keyboard-navigation.d.ts +7 -5
- package/lib/parts/use-menu-keyboard-navigation.js +98 -99
- package/lib/public-api.p.css +52 -76
- package/lib/public-api.pcss +52 -76
- package/lib/types.d.ts +87 -0
- package/llm/components/menu.md +79 -8
- package/package.json +8 -8
package/lib/menu.js
CHANGED
|
@@ -1,65 +1,149 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import React from 'react';
|
|
2
|
+
import React, { useRef } from 'react';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import cn from 'classnames';
|
|
5
5
|
import { MenuProvider } from './parts/menu-context.js';
|
|
6
6
|
import styles from './menu.p.module.css.js';
|
|
7
7
|
import { useMenuKeyboardNavigation } from './parts/use-menu-keyboard-navigation.js';
|
|
8
8
|
|
|
9
|
-
const
|
|
9
|
+
const MenuListbox = _ref => {
|
|
10
10
|
let {
|
|
11
|
-
|
|
11
|
+
activateFirstItem,
|
|
12
|
+
tag: Tag,
|
|
12
13
|
itemTag,
|
|
13
14
|
iconPlacement,
|
|
14
15
|
disabled,
|
|
15
|
-
size
|
|
16
|
+
size,
|
|
16
17
|
mode,
|
|
17
|
-
disableCursor = false,
|
|
18
18
|
theme,
|
|
19
|
-
enableKeyboardNavigation = false,
|
|
20
|
-
activateFirstItem = false,
|
|
21
19
|
className,
|
|
22
20
|
wrapItemsWithLi,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
resizeIcons,
|
|
22
|
+
role,
|
|
23
|
+
onKeyDown,
|
|
24
|
+
onMouseLeave,
|
|
25
|
+
tabIndex,
|
|
26
|
+
...props
|
|
26
27
|
} = _ref;
|
|
27
|
-
const
|
|
28
|
+
const menuRef = useRef(null);
|
|
28
29
|
const {
|
|
29
|
-
|
|
30
|
+
currentActiveItemEl,
|
|
31
|
+
setCurrentActiveItemEl,
|
|
30
32
|
registerItem,
|
|
31
33
|
unregisterItem,
|
|
32
|
-
|
|
34
|
+
handleItemFocus,
|
|
35
|
+
handleItemKeyDown,
|
|
36
|
+
handleItemMouseEnter
|
|
33
37
|
} = useMenuKeyboardNavigation({
|
|
34
|
-
|
|
35
|
-
activateFirstItem,
|
|
36
|
-
returnFocusOnUnmount
|
|
38
|
+
activateFirstItem
|
|
37
39
|
});
|
|
40
|
+
|
|
41
|
+
const handleMenuKeyDown = e => {
|
|
42
|
+
onKeyDown?.(e);
|
|
43
|
+
|
|
44
|
+
if (e.defaultPrevented || e.target !== e.currentTarget) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
handleItemKeyDown(e, currentActiveItemEl ?? undefined);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const handleMenuMouseLeave = e => {
|
|
52
|
+
onMouseLeave?.(e);
|
|
53
|
+
|
|
54
|
+
if (e.defaultPrevented) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setCurrentActiveItemEl(null);
|
|
59
|
+
menuRef.current?.focus({
|
|
60
|
+
preventScroll: true
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
38
64
|
return /*#__PURE__*/React.createElement(MenuProvider, {
|
|
39
65
|
itemTag: itemTag,
|
|
40
66
|
iconPlacement: iconPlacement,
|
|
41
67
|
disabled: disabled,
|
|
42
68
|
size: size,
|
|
43
|
-
disableCursor: disableCursor || isKeyboardNavigating,
|
|
44
69
|
mode: mode,
|
|
45
70
|
theme: theme,
|
|
71
|
+
wrapWithLi: wrapItemsWithLi ?? Tag === 'ul',
|
|
72
|
+
resizeIcons: resizeIcons,
|
|
73
|
+
keyboardNavigationEnabled: true,
|
|
74
|
+
currentActiveItemEl: currentActiveItemEl,
|
|
46
75
|
registerItem: registerItem,
|
|
47
76
|
unregisterItem: unregisterItem,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
77
|
+
onItemFocus: handleItemFocus,
|
|
78
|
+
onItemKeyDown: handleItemKeyDown,
|
|
79
|
+
onItemMouseEnter: handleItemMouseEnter
|
|
80
|
+
}, /*#__PURE__*/React.createElement(Tag, { ...props,
|
|
81
|
+
className: cn(styles.keyboardNavigationEnabled, styles.menu, className),
|
|
82
|
+
onKeyDown: handleMenuKeyDown,
|
|
83
|
+
onMouseLeave: handleMenuMouseLeave,
|
|
84
|
+
role: role ?? 'listbox',
|
|
85
|
+
tabIndex: currentActiveItemEl ? -1 : tabIndex ?? 0,
|
|
86
|
+
ref: menuRef
|
|
87
|
+
}));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const MenuRegular = _ref2 => {
|
|
91
|
+
let {
|
|
92
|
+
tag: Tag,
|
|
93
|
+
itemTag,
|
|
94
|
+
iconPlacement,
|
|
95
|
+
disabled,
|
|
96
|
+
size,
|
|
97
|
+
mode,
|
|
98
|
+
theme,
|
|
99
|
+
className,
|
|
100
|
+
wrapItemsWithLi,
|
|
101
|
+
resizeIcons,
|
|
102
|
+
...props
|
|
103
|
+
} = _ref2;
|
|
104
|
+
return /*#__PURE__*/React.createElement(MenuProvider, {
|
|
105
|
+
itemTag: itemTag,
|
|
106
|
+
iconPlacement: iconPlacement,
|
|
107
|
+
disabled: disabled,
|
|
108
|
+
size: size,
|
|
109
|
+
mode: mode,
|
|
110
|
+
theme: theme,
|
|
111
|
+
wrapWithLi: wrapItemsWithLi ?? Tag === 'ul',
|
|
112
|
+
resizeIcons: resizeIcons,
|
|
113
|
+
keyboardNavigationEnabled: false,
|
|
114
|
+
currentActiveItemEl: null,
|
|
115
|
+
registerItem: null,
|
|
116
|
+
unregisterItem: null,
|
|
117
|
+
onItemFocus: null,
|
|
118
|
+
onItemKeyDown: null,
|
|
119
|
+
onItemMouseEnter: null
|
|
52
120
|
}, /*#__PURE__*/React.createElement(Tag, {
|
|
53
|
-
className: cn(
|
|
54
|
-
...
|
|
121
|
+
className: cn(styles.keyboardNavigationDisabled, styles.menu, className),
|
|
122
|
+
...props
|
|
55
123
|
}));
|
|
56
124
|
};
|
|
57
125
|
|
|
126
|
+
const Menu = _ref3 => {
|
|
127
|
+
let {
|
|
128
|
+
enableKeyboardNavigation = false,
|
|
129
|
+
activateFirstItem = false,
|
|
130
|
+
tag = 'ul',
|
|
131
|
+
...props
|
|
132
|
+
} = _ref3;
|
|
133
|
+
return enableKeyboardNavigation ? /*#__PURE__*/React.createElement(MenuListbox, {
|
|
134
|
+
activateFirstItem: activateFirstItem,
|
|
135
|
+
tag: tag,
|
|
136
|
+
...props
|
|
137
|
+
}) : /*#__PURE__*/React.createElement(MenuRegular, {
|
|
138
|
+
tag: tag,
|
|
139
|
+
...props
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
|
|
58
143
|
Menu.propTypes = {
|
|
59
144
|
size: PropTypes.oneOf(['l', 'm', 's']),
|
|
60
145
|
mode: PropTypes.oneOf(['clear', 'classic', 'rock']),
|
|
61
146
|
theme: PropTypes.oneOf(['light', 'dark']),
|
|
62
|
-
disableCursor: PropTypes.bool,
|
|
63
147
|
disabled: PropTypes.bool,
|
|
64
148
|
resizeIcons: PropTypes.bool,
|
|
65
149
|
iconPlacement: PropTypes.oneOf(['left', 'right']),
|
package/lib/menu.p.module.css.js
CHANGED
|
@@ -1,30 +1,37 @@
|
|
|
1
1
|
var styles = {
|
|
2
|
-
"themeLight": "
|
|
3
|
-
"themeDark": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
2
|
+
"themeLight": "_themeLight_1t76rai_8",
|
|
3
|
+
"themeDark": "_themeDark_1t76rai_11",
|
|
4
|
+
"menu": "_menu_1t76rai_15",
|
|
5
|
+
"sizeS": "_sizeS_1t76rai_21",
|
|
6
|
+
"sizeM": "_sizeM_1t76rai_24",
|
|
7
|
+
"sizeL": "_sizeL_1t76rai_27",
|
|
8
|
+
"modeClassic": "_modeClassic_1t76rai_31",
|
|
9
|
+
"modeRock": "_modeRock_1t76rai_34",
|
|
10
|
+
"modeClear": "_modeClear_1t76rai_37",
|
|
11
|
+
"iconPlacementLeft": "_iconPlacementLeft_1t76rai_41",
|
|
12
|
+
"iconPlacementRight": "_iconPlacementRight_1t76rai_45",
|
|
13
|
+
"wrapper": "_wrapper_1t76rai_49",
|
|
14
|
+
"hoverIcon": "_hoverIcon_1t76rai_53",
|
|
15
|
+
"hoverIconNoReserve": "_hoverIconNoReserve_1t76rai_56",
|
|
16
|
+
"menuItem": "_menuItem_1t76rai_61",
|
|
17
|
+
"keyboardNavigationDisabled": "_keyboardNavigationDisabled_1t76rai_98",
|
|
18
|
+
"selected": "_selected_1t76rai_112",
|
|
19
|
+
"keyboardNavigationEnabled": "_keyboardNavigationEnabled_1t76rai_119",
|
|
20
|
+
"hideCustomIconOnHover": "_hideCustomIconOnHover_1t76rai_130",
|
|
21
|
+
"customIcon": "_customIcon_1t76rai_132",
|
|
22
|
+
"hideSelectedIconOnHover": "_hideSelectedIconOnHover_1t76rai_137",
|
|
23
|
+
"selectedIcon": "_selectedIcon_1t76rai_139",
|
|
24
|
+
"disabled": "_disabled_1t76rai_144",
|
|
25
|
+
"contentWrapper": "_contentWrapper_1t76rai_151",
|
|
26
|
+
"content": "_content_1t76rai_151",
|
|
27
|
+
"icon": "_icon_1t76rai_41",
|
|
28
|
+
"resizedIcon": "_resizedIcon_1t76rai_169",
|
|
29
|
+
"divider": "_divider_1t76rai_177",
|
|
30
|
+
"groupHeaderThemeLight": "_groupHeaderThemeLight_1t76rai_191",
|
|
31
|
+
"groupHeaderThemeDark": "_groupHeaderThemeDark_1t76rai_194",
|
|
32
|
+
"groupHeaderSizeL": "_groupHeaderSizeL_1t76rai_198",
|
|
33
|
+
"groupHeaderSizeM": "_groupHeaderSizeM_1t76rai_201",
|
|
34
|
+
"groupHeaderSizeS": "_groupHeaderSizeS_1t76rai_204",
|
|
35
|
+
"groupHeader": "_groupHeader_1t76rai_191"
|
|
29
36
|
};
|
|
30
37
|
export { styles as default };
|
package/lib/parts/divider.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
4
|
-
export
|
|
5
|
-
theme?: Theme;
|
|
6
|
-
className?: string;
|
|
7
|
-
}
|
|
3
|
+
import type { DividerProps } from '../types';
|
|
4
|
+
export type { DividerProps } from '../types';
|
|
8
5
|
declare const Divider: {
|
|
9
6
|
({ className, theme, ...restProps }: DividerProps): React.JSX.Element;
|
|
10
7
|
propTypes: {
|
package/lib/parts/divider.js
CHANGED
|
@@ -20,6 +20,7 @@ const Divider = _ref => {
|
|
|
20
20
|
const actualTheme = useThemeWithUndefined(menuContext.theme ?? theme);
|
|
21
21
|
return /*#__PURE__*/React.createElement("hr", {
|
|
22
22
|
className: cn(styles.divider, THEME_CLASS[actualTheme], className),
|
|
23
|
+
role: menuContext.keyboardNavigationEnabled ? 'presentation' : undefined,
|
|
23
24
|
...restProps
|
|
24
25
|
});
|
|
25
26
|
};
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export interface GroupHeaderProps {
|
|
6
|
-
theme?: Theme;
|
|
7
|
-
size?: MenuItemSize;
|
|
8
|
-
text?: React.ReactNode;
|
|
9
|
-
className?: string;
|
|
10
|
-
}
|
|
3
|
+
import type { GroupHeaderProps } from '../types';
|
|
4
|
+
export type { GroupHeaderProps } from '../types';
|
|
11
5
|
declare function GroupHeader({ className, text, size: propsSize, theme: propsTheme }: GroupHeaderProps): React.JSX.Element;
|
|
12
6
|
declare namespace GroupHeader {
|
|
13
7
|
var propTypes: {
|
|
@@ -27,7 +27,8 @@ function GroupHeader(_ref) {
|
|
|
27
27
|
const actualTheme = useThemeWithUndefined(menuContext.theme ?? propsTheme);
|
|
28
28
|
return /*#__PURE__*/React.createElement(Tag, {
|
|
29
29
|
className: cn(styles.groupHeader, SIZE_CLASS[menuContext.size ?? propsSize], THEME_CLASS[actualTheme], className),
|
|
30
|
-
"data-rs-internal": 'menu__group-header'
|
|
30
|
+
"data-rs-internal": 'menu__group-header',
|
|
31
|
+
role: menuContext.keyboardNavigationEnabled ? 'presentation' : undefined
|
|
31
32
|
}, text);
|
|
32
33
|
}
|
|
33
34
|
|
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
export type
|
|
4
|
-
export type MenuItemIconPlacement = 'left' | 'right';
|
|
5
|
-
export type MenuItemMode = 'clear' | 'classic' | 'rock';
|
|
6
|
-
export interface MenuContextValue {
|
|
7
|
-
iconPlacement?: MenuItemIconPlacement;
|
|
8
|
-
disabled?: boolean;
|
|
9
|
-
disableCursor?: boolean;
|
|
10
|
-
size?: MenuItemSize;
|
|
11
|
-
mode?: MenuItemMode;
|
|
12
|
-
theme?: Theme;
|
|
13
|
-
itemTag?: React.ElementType;
|
|
14
|
-
wrapWithLi: boolean;
|
|
15
|
-
registerItem?: (ref: HTMLElement) => void;
|
|
16
|
-
unregisterItem?: (ref: HTMLElement) => void;
|
|
17
|
-
activeItemRef?: HTMLElement;
|
|
18
|
-
isKeyboardNavigating: boolean;
|
|
19
|
-
resizeIcons?: boolean;
|
|
20
|
-
}
|
|
2
|
+
import type { MenuContextValue } from '../types';
|
|
3
|
+
export type { MenuContextValue, MenuItemMode, MenuItemIconPlacement, MenuItemSize } from '../types';
|
|
21
4
|
export declare const DEFAULT_MENU_CONTEXT: MenuContextValue;
|
|
22
5
|
export declare const MenuContext: React.Context<MenuContextValue>;
|
|
23
6
|
export declare const useMenuContext: () => MenuContextValue;
|
|
@@ -3,12 +3,14 @@ import React, { useContext } from 'react';
|
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
const DEFAULT_MENU_CONTEXT = {
|
|
5
5
|
disabled: false,
|
|
6
|
-
|
|
6
|
+
keyboardNavigationEnabled: false,
|
|
7
7
|
wrapWithLi: false,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
registerItem: null,
|
|
9
|
+
unregisterItem: null,
|
|
10
|
+
currentActiveItemEl: null,
|
|
11
|
+
onItemFocus: null,
|
|
12
|
+
onItemKeyDown: null,
|
|
13
|
+
onItemMouseEnter: null
|
|
12
14
|
};
|
|
13
15
|
const MenuContext = /*#__PURE__*/React.createContext(DEFAULT_MENU_CONTEXT);
|
|
14
16
|
|
|
@@ -18,7 +20,6 @@ const MenuProvider = _ref => {
|
|
|
18
20
|
let {
|
|
19
21
|
children,
|
|
20
22
|
disabled = DEFAULT_MENU_CONTEXT.disabled,
|
|
21
|
-
isKeyboardNavigating = DEFAULT_MENU_CONTEXT.isKeyboardNavigating,
|
|
22
23
|
wrapWithLi = DEFAULT_MENU_CONTEXT.wrapWithLi,
|
|
23
24
|
registerItem = DEFAULT_MENU_CONTEXT.registerItem,
|
|
24
25
|
unregisterItem = DEFAULT_MENU_CONTEXT.unregisterItem,
|
|
@@ -27,7 +28,6 @@ const MenuProvider = _ref => {
|
|
|
27
28
|
return /*#__PURE__*/React.createElement(MenuContext.Provider, {
|
|
28
29
|
value: {
|
|
29
30
|
disabled,
|
|
30
|
-
isKeyboardNavigating,
|
|
31
31
|
wrapWithLi,
|
|
32
32
|
registerItem,
|
|
33
33
|
unregisterItem,
|
|
@@ -40,7 +40,6 @@ MenuProvider.propTypes = {
|
|
|
40
40
|
size: PropTypes.oneOf(['l', 'm', 's']),
|
|
41
41
|
mode: PropTypes.oneOf(['clear', 'classic', 'rock']),
|
|
42
42
|
theme: PropTypes.oneOf(['light', 'dark']),
|
|
43
|
-
disableCursor: PropTypes.bool,
|
|
44
43
|
disabled: PropTypes.bool,
|
|
45
44
|
iconPlacement: PropTypes.oneOf(['left', 'right']),
|
|
46
45
|
itemTag: PropTypes.elementType
|
package/lib/parts/menu-item.d.ts
CHANGED
|
@@ -1,21 +1,33 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { JSX
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export interface MenuItemProps extends Omit<AllHTMLAttributes<Element>, 'size'> {
|
|
2
|
+
import type { JSX } from 'react';
|
|
3
|
+
export type { MenuItemProps } from '../types';
|
|
4
|
+
export declare const MenuItem: React.ForwardRefExoticComponent<{
|
|
6
5
|
className?: string;
|
|
7
6
|
tag?: React.ElementType;
|
|
8
7
|
icon?: JSX.Element;
|
|
9
|
-
size?: MenuItemSize;
|
|
10
|
-
mode?: MenuItemMode;
|
|
11
|
-
theme?: Theme;
|
|
8
|
+
size?: import("./menu-context").MenuItemSize;
|
|
9
|
+
mode?: import("./menu-context").MenuItemMode;
|
|
10
|
+
theme?: import("@rescui/ui-contexts").Theme;
|
|
12
11
|
disabled?: boolean;
|
|
13
|
-
disableCursor?: boolean;
|
|
14
12
|
selected?: boolean;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
children?: ReactNode;
|
|
13
|
+
iconPlacement?: import("./menu-context").MenuItemIconPlacement;
|
|
14
|
+
children?: React.ReactNode;
|
|
18
15
|
key?: string;
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
'data-test'?: string;
|
|
17
|
+
hoverIcon?: JSX.Element;
|
|
18
|
+
} & Omit<React.AllHTMLAttributes<Element>, keyof {
|
|
19
|
+
className?: string;
|
|
20
|
+
tag?: React.ElementType;
|
|
21
|
+
icon?: JSX.Element;
|
|
22
|
+
size?: import("./menu-context").MenuItemSize;
|
|
23
|
+
mode?: import("./menu-context").MenuItemMode;
|
|
24
|
+
theme?: import("@rescui/ui-contexts").Theme;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
selected?: boolean;
|
|
27
|
+
iconPlacement?: import("./menu-context").MenuItemIconPlacement;
|
|
28
|
+
children?: React.ReactNode;
|
|
29
|
+
key?: string;
|
|
30
|
+
'data-test'?: string;
|
|
31
|
+
hoverIcon?: JSX.Element;
|
|
32
|
+
}> & React.RefAttributes<HTMLElement>>;
|
|
21
33
|
export default MenuItem;
|
package/lib/parts/menu-item.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import React, { useState,
|
|
2
|
+
import React, { useState, cloneElement, useEffect } from 'react';
|
|
3
3
|
import cn from 'classnames';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import { useThemeWithUndefined } from '@rescui/ui-contexts';
|
|
6
|
+
import CheckOutlineIcon from '../_virtual/check-outline.js';
|
|
6
7
|
import styles from '../menu.p.module.css.js';
|
|
7
8
|
import { useMenuContext } from './menu-context.js';
|
|
8
9
|
const ICON_PLACEMENT_STYLES = {
|
|
@@ -22,6 +23,11 @@ const SIZE_STYLES = {
|
|
|
22
23
|
const THEME_STYLES = {
|
|
23
24
|
light: styles.themeLight,
|
|
24
25
|
dark: styles.themeDark
|
|
26
|
+
};
|
|
27
|
+
const HOVER_ICON_WILL_REPLACE_STYLES = {
|
|
28
|
+
custom: styles.hideCustomIconOnHover,
|
|
29
|
+
selected: styles.hideSelectedIconOnHover,
|
|
30
|
+
none: ''
|
|
25
31
|
}; // eslint-disable-next-line complexity
|
|
26
32
|
|
|
27
33
|
const MenuItemInner = (_ref, ref) => {
|
|
@@ -34,27 +40,29 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
34
40
|
mode = 'classic',
|
|
35
41
|
theme,
|
|
36
42
|
disabled,
|
|
37
|
-
disableCursor,
|
|
38
43
|
selected,
|
|
39
|
-
|
|
40
|
-
/* @private */
|
|
41
|
-
highlighted,
|
|
42
44
|
iconPlacement = 'left',
|
|
45
|
+
onFocus,
|
|
46
|
+
onKeyDown,
|
|
47
|
+
onMouseEnter,
|
|
48
|
+
role,
|
|
49
|
+
tabIndex,
|
|
50
|
+
hoverIcon,
|
|
43
51
|
...restProps
|
|
44
52
|
} = _ref;
|
|
45
53
|
const {
|
|
46
54
|
unregisterItem,
|
|
47
55
|
registerItem,
|
|
48
|
-
|
|
49
|
-
|
|
56
|
+
currentActiveItemEl,
|
|
57
|
+
keyboardNavigationEnabled,
|
|
58
|
+
onItemFocus,
|
|
59
|
+
onItemKeyDown,
|
|
60
|
+
onItemMouseEnter,
|
|
50
61
|
wrapWithLi,
|
|
51
62
|
...menuContext
|
|
52
63
|
} = useMenuContext();
|
|
53
64
|
const actualTheme = useThemeWithUndefined(menuContext.theme ?? theme);
|
|
54
65
|
const [thisRef, setThisRef] = useState(null);
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
return () => unregisterItem(thisRef);
|
|
57
|
-
}, [unregisterItem, thisRef]);
|
|
58
66
|
let autoTag = 'span';
|
|
59
67
|
|
|
60
68
|
if (restProps.href) {
|
|
@@ -67,17 +75,37 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
67
75
|
const actualIconPlacement = menuContext.iconPlacement ?? iconPlacement ?? 'left';
|
|
68
76
|
const actualMode = menuContext.mode ?? mode;
|
|
69
77
|
const actualSize = menuContext.size ?? size;
|
|
70
|
-
const actualDisableCursor = menuContext.disableCursor ?? disableCursor;
|
|
71
78
|
const resizeIcons = menuContext.resizeIcons ?? false;
|
|
72
|
-
const
|
|
73
|
-
|
|
79
|
+
const actualDisabled = menuContext.disabled || disabled;
|
|
80
|
+
const iconElement = /*#__PURE__*/React.isValidElement(icon) ? /*#__PURE__*/cloneElement(icon, {
|
|
81
|
+
className: cn(icon.props.className, styles.icon, styles.customIcon, resizeIcons && styles.resizedIcon),
|
|
74
82
|
'data-render-all-sizes': true
|
|
75
83
|
}) : null;
|
|
76
|
-
const
|
|
84
|
+
const hasHoverIcon = /*#__PURE__*/React.isValidElement(hoverIcon);
|
|
85
|
+
const rovingTabIndex = currentActiveItemEl === thisRef ? 0 : -1;
|
|
86
|
+
let resolvedTabIndex = tabIndex ?? 0;
|
|
87
|
+
|
|
88
|
+
if (keyboardNavigationEnabled) {
|
|
89
|
+
resolvedTabIndex = rovingTabIndex;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (actualDisabled) {
|
|
93
|
+
resolvedTabIndex = -1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!thisRef || actualDisabled || !registerItem) {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
registerItem(thisRef);
|
|
102
|
+
return () => unregisterItem?.(thisRef);
|
|
103
|
+
}, [actualDisabled, registerItem, thisRef, unregisterItem]);
|
|
77
104
|
|
|
78
105
|
const handleRef = r => {
|
|
79
|
-
|
|
80
|
-
|
|
106
|
+
if (r) {
|
|
107
|
+
setThisRef(r);
|
|
108
|
+
}
|
|
81
109
|
|
|
82
110
|
if (typeof ref === 'function') {
|
|
83
111
|
ref(r);
|
|
@@ -87,31 +115,71 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
87
115
|
};
|
|
88
116
|
|
|
89
117
|
const handleKeyDown = e => {
|
|
90
|
-
|
|
91
|
-
|
|
118
|
+
onKeyDown?.(e);
|
|
119
|
+
|
|
120
|
+
if (e.defaultPrevented || !onItemKeyDown) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
92
123
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
124
|
+
if (thisRef) {
|
|
125
|
+
onItemKeyDown(e, thisRef);
|
|
96
126
|
}
|
|
97
127
|
};
|
|
98
128
|
|
|
129
|
+
const handleFocus = e => {
|
|
130
|
+
onFocus?.(e);
|
|
131
|
+
|
|
132
|
+
if (onItemFocus && thisRef) {
|
|
133
|
+
onItemFocus(thisRef);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleMouseEnter = e => {
|
|
138
|
+
onMouseEnter?.(e);
|
|
139
|
+
|
|
140
|
+
if (onItemMouseEnter && thisRef) {
|
|
141
|
+
onItemMouseEnter(thisRef);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
let hoverIconWillReplace = 'none';
|
|
146
|
+
|
|
147
|
+
if (hasHoverIcon && iconElement && actualIconPlacement === 'right') {
|
|
148
|
+
hoverIconWillReplace = 'custom';
|
|
149
|
+
} else if (hasHoverIcon && selected) {
|
|
150
|
+
hoverIconWillReplace = 'selected';
|
|
151
|
+
}
|
|
152
|
+
|
|
99
153
|
const Wrapper = wrapWithLi ? 'li' : 'div';
|
|
100
154
|
return /*#__PURE__*/React.createElement(Wrapper, {
|
|
101
155
|
className: cn(styles.wrapper, className, ICON_PLACEMENT_STYLES[actualIconPlacement], MODE_STYLES[actualMode], SIZE_STYLES[actualSize], THEME_STYLES[actualTheme]),
|
|
102
156
|
"data-test": 'menu-item__wrapper',
|
|
103
|
-
"data-rs-internal": 'menu__menu-item'
|
|
104
|
-
|
|
157
|
+
"data-rs-internal": 'menu__menu-item',
|
|
158
|
+
role: keyboardNavigationEnabled ? 'presentation' : undefined
|
|
159
|
+
}, /*#__PURE__*/React.createElement(Tag, { ...restProps,
|
|
160
|
+
onFocus: handleFocus,
|
|
105
161
|
onKeyDown: handleKeyDown,
|
|
162
|
+
onMouseEnter: handleMouseEnter,
|
|
106
163
|
ref: handleRef,
|
|
107
|
-
className: cn(styles.menuItem,
|
|
108
|
-
"data-test": 'menu-item',
|
|
164
|
+
className: cn(styles.menuItem, actualDisabled && styles.disabled, selected && styles.selected, HOVER_ICON_WILL_REPLACE_STYLES[hoverIconWillReplace]),
|
|
165
|
+
"data-test": restProps['data-test'] ?? 'menu-item',
|
|
109
166
|
"data-rs-internal": 'menu__menu-item__inner',
|
|
110
|
-
|
|
111
|
-
|
|
167
|
+
role: role ?? (keyboardNavigationEnabled ? 'option' : undefined),
|
|
168
|
+
"aria-selected": keyboardNavigationEnabled && selected !== undefined ? selected : restProps['aria-selected'],
|
|
169
|
+
"aria-disabled": keyboardNavigationEnabled && actualDisabled ? true : restProps['aria-disabled'],
|
|
170
|
+
tabIndex: resolvedTabIndex
|
|
112
171
|
}, iconElement, /*#__PURE__*/React.createElement("span", {
|
|
172
|
+
className: styles.contentWrapper
|
|
173
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
113
174
|
className: styles.content
|
|
114
|
-
}, children)
|
|
175
|
+
}, children), selected && /*#__PURE__*/React.createElement(CheckOutlineIcon, {
|
|
176
|
+
className: cn(styles.icon, styles.selectedIcon, resizeIcons && styles.resizedIcon),
|
|
177
|
+
"data-test": 'menu-item__selected-icon',
|
|
178
|
+
"data-render-all-sizes": true
|
|
179
|
+
}), hasHoverIcon && /*#__PURE__*/React.cloneElement(hoverIcon, {
|
|
180
|
+
className: cn(hoverIcon.props.className, styles.icon, styles.hoverIcon, resizeIcons && styles.resizedIcon, hoverIconWillReplace !== 'none' && styles.hoverIconNoReserve),
|
|
181
|
+
'data-render-all-sizes': true
|
|
182
|
+
}))));
|
|
115
183
|
};
|
|
116
184
|
|
|
117
185
|
const MenuItem = /*#__PURE__*/React.forwardRef(MenuItemInner);
|
|
@@ -119,15 +187,11 @@ MenuItem.propTypes = {
|
|
|
119
187
|
size: PropTypes.oneOf(['l', 'm', 's']),
|
|
120
188
|
mode: PropTypes.oneOf(['clear', 'classic', 'rock']),
|
|
121
189
|
theme: PropTypes.oneOf(['light', 'dark']),
|
|
122
|
-
onClick: PropTypes.func,
|
|
123
190
|
disabled: PropTypes.bool,
|
|
124
|
-
disableCursor: PropTypes.bool,
|
|
125
191
|
selected: PropTypes.bool,
|
|
126
|
-
|
|
127
|
-
/** @ignore */
|
|
128
|
-
highlighted: PropTypes.bool,
|
|
129
192
|
icon: PropTypes.element,
|
|
130
193
|
iconPlacement: PropTypes.oneOf(['left', 'right']),
|
|
131
|
-
tag: PropTypes.elementType
|
|
194
|
+
tag: PropTypes.elementType,
|
|
195
|
+
hoverIcon: PropTypes.element
|
|
132
196
|
};
|
|
133
197
|
export { MenuItem, MenuItem as default };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare function getFirstItem(sortedItems: HTMLElement[]): HTMLElement;
|
|
2
2
|
export declare function getLastItem(sortedItems: HTMLElement[]): HTMLElement;
|
|
3
|
-
export declare function getNextItem(sortedItems: HTMLElement[], activeItem
|
|
4
|
-
export declare function getPrevItem(sortedItems: HTMLElement[], activeItem
|
|
3
|
+
export declare function getNextItem(sortedItems: HTMLElement[], activeItem?: HTMLElement): HTMLElement;
|
|
4
|
+
export declare function getPrevItem(sortedItems: HTMLElement[], activeItem?: HTMLElement): HTMLElement;
|
|
5
5
|
export declare function htmlElementsComparator(a: HTMLElement, b: HTMLElement): 0 | 1 | -1;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
1
2
|
interface UseMenuKeyboardNavigationParams {
|
|
2
|
-
enableKeyboardNavigation: boolean;
|
|
3
3
|
activateFirstItem: boolean;
|
|
4
|
-
returnFocusOnUnmount: boolean;
|
|
5
4
|
}
|
|
6
|
-
export declare function useMenuKeyboardNavigation({
|
|
7
|
-
|
|
5
|
+
export declare function useMenuKeyboardNavigation({ activateFirstItem }: UseMenuKeyboardNavigationParams): {
|
|
6
|
+
currentActiveItemEl: HTMLElement;
|
|
7
|
+
setCurrentActiveItemEl: React.Dispatch<React.SetStateAction<HTMLElement>>;
|
|
8
8
|
registerItem: (ref: HTMLElement) => void;
|
|
9
9
|
unregisterItem: (ref: HTMLElement) => void;
|
|
10
|
-
|
|
10
|
+
handleItemFocus: (ref: HTMLElement) => void;
|
|
11
|
+
handleItemKeyDown: (e: React.KeyboardEvent<HTMLElement>, ref?: HTMLElement) => void;
|
|
12
|
+
handleItemMouseEnter: (ref: HTMLElement) => void;
|
|
11
13
|
};
|
|
12
14
|
export {};
|