@rescui/menu 0.13.6-RUI-296-Build-docs-md-files-for-each-docs-section-2a311c841.18 → 0.13.6-RUI-293-Update-menu-component-7a032357e.20
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 +175 -76
- package/lib/index.d.ts +1 -5
- package/lib/menu.d.ts +17 -11
- package/lib/menu.js +123 -24
- package/lib/menu.p.module.css.js +28 -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 +23 -13
- package/lib/parts/menu-item.js +62 -27
- 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 -52
- package/lib/public-api.pcss +52 -52
- package/lib/types.d.ts +64 -0
- package/llm/components/menu.md +309 -0
- package/llm/index.md +2 -0
- package/package.json +5 -4
package/lib/menu.js
CHANGED
|
@@ -1,65 +1,164 @@
|
|
|
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
|
+
disabled = false,
|
|
132
|
+
size = 'm',
|
|
133
|
+
mode = 'classic',
|
|
134
|
+
iconPlacement = 'left',
|
|
135
|
+
resizeIcons = false,
|
|
136
|
+
...props
|
|
137
|
+
} = _ref3;
|
|
138
|
+
return enableKeyboardNavigation ? /*#__PURE__*/React.createElement(MenuListbox, {
|
|
139
|
+
activateFirstItem: activateFirstItem,
|
|
140
|
+
tag: tag,
|
|
141
|
+
disabled: disabled,
|
|
142
|
+
size: size,
|
|
143
|
+
mode: mode,
|
|
144
|
+
iconPlacement: iconPlacement,
|
|
145
|
+
resizeIcons: resizeIcons,
|
|
146
|
+
...props
|
|
147
|
+
}) : /*#__PURE__*/React.createElement(MenuRegular, {
|
|
148
|
+
tag: tag,
|
|
149
|
+
disabled: disabled,
|
|
150
|
+
size: size,
|
|
151
|
+
mode: mode,
|
|
152
|
+
iconPlacement: iconPlacement,
|
|
153
|
+
resizeIcons: resizeIcons,
|
|
154
|
+
...props
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
|
|
58
158
|
Menu.propTypes = {
|
|
59
159
|
size: PropTypes.oneOf(['l', 'm', 's']),
|
|
60
160
|
mode: PropTypes.oneOf(['clear', 'classic', 'rock']),
|
|
61
161
|
theme: PropTypes.oneOf(['light', 'dark']),
|
|
62
|
-
disableCursor: PropTypes.bool,
|
|
63
162
|
disabled: PropTypes.bool,
|
|
64
163
|
resizeIcons: PropTypes.bool,
|
|
65
164
|
iconPlacement: PropTypes.oneOf(['left', 'right']),
|
package/lib/menu.p.module.css.js
CHANGED
|
@@ -1,30 +1,31 @@
|
|
|
1
1
|
var styles = {
|
|
2
|
-
"themeLight": "
|
|
3
|
-
"themeDark": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"disabled": "
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
2
|
+
"themeLight": "_themeLight_1bzmk9l_8",
|
|
3
|
+
"themeDark": "_themeDark_1bzmk9l_11",
|
|
4
|
+
"menu": "_menu_1bzmk9l_15",
|
|
5
|
+
"sizeS": "_sizeS_1bzmk9l_21",
|
|
6
|
+
"sizeM": "_sizeM_1bzmk9l_24",
|
|
7
|
+
"sizeL": "_sizeL_1bzmk9l_27",
|
|
8
|
+
"modeClassic": "_modeClassic_1bzmk9l_31",
|
|
9
|
+
"modeRock": "_modeRock_1bzmk9l_34",
|
|
10
|
+
"modeClear": "_modeClear_1bzmk9l_37",
|
|
11
|
+
"iconPlacementLeft": "_iconPlacementLeft_1bzmk9l_41",
|
|
12
|
+
"iconPlacementRight": "_iconPlacementRight_1bzmk9l_45",
|
|
13
|
+
"wrapper": "_wrapper_1bzmk9l_49",
|
|
14
|
+
"menuItem": "_menuItem_1bzmk9l_53",
|
|
15
|
+
"keyboardNavigationDisabled": "_keyboardNavigationDisabled_1bzmk9l_90",
|
|
16
|
+
"selected": "_selected_1bzmk9l_104",
|
|
17
|
+
"keyboardNavigationEnabled": "_keyboardNavigationEnabled_1bzmk9l_111",
|
|
18
|
+
"disabled": "_disabled_1bzmk9l_117",
|
|
19
|
+
"contentWrapper": "_contentWrapper_1bzmk9l_124",
|
|
20
|
+
"content": "_content_1bzmk9l_124",
|
|
21
|
+
"icon": "_icon_1bzmk9l_41",
|
|
22
|
+
"resizedIcon": "_resizedIcon_1bzmk9l_142",
|
|
23
|
+
"divider": "_divider_1bzmk9l_150",
|
|
24
|
+
"groupHeaderThemeLight": "_groupHeaderThemeLight_1bzmk9l_164",
|
|
25
|
+
"groupHeaderThemeDark": "_groupHeaderThemeDark_1bzmk9l_167",
|
|
26
|
+
"groupHeaderSizeL": "_groupHeaderSizeL_1bzmk9l_171",
|
|
27
|
+
"groupHeaderSizeM": "_groupHeaderSizeM_1bzmk9l_174",
|
|
28
|
+
"groupHeaderSizeS": "_groupHeaderSizeS_1bzmk9l_177",
|
|
29
|
+
"groupHeader": "_groupHeader_1bzmk9l_164"
|
|
29
30
|
};
|
|
30
31
|
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,31 @@
|
|
|
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
|
+
} & Omit<React.AllHTMLAttributes<Element>, keyof {
|
|
18
|
+
className?: string;
|
|
19
|
+
tag?: React.ElementType;
|
|
20
|
+
icon?: JSX.Element;
|
|
21
|
+
size?: import("./menu-context").MenuItemSize;
|
|
22
|
+
mode?: import("./menu-context").MenuItemMode;
|
|
23
|
+
theme?: import("@rescui/ui-contexts").Theme;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
selected?: boolean;
|
|
26
|
+
iconPlacement?: import("./menu-context").MenuItemIconPlacement;
|
|
27
|
+
children?: React.ReactNode;
|
|
28
|
+
key?: string;
|
|
29
|
+
'data-test'?: string;
|
|
30
|
+
}> & React.RefAttributes<HTMLElement>>;
|
|
21
31
|
export default MenuItem;
|
package/lib/parts/menu-item.js
CHANGED
|
@@ -3,6 +3,7 @@ import React, { useState, useEffect, cloneElement } 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 = {
|
|
@@ -34,25 +35,33 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
34
35
|
mode = 'classic',
|
|
35
36
|
theme,
|
|
36
37
|
disabled,
|
|
37
|
-
disableCursor,
|
|
38
38
|
selected,
|
|
39
|
-
|
|
40
|
-
/* @private */
|
|
41
|
-
highlighted,
|
|
42
39
|
iconPlacement = 'left',
|
|
40
|
+
onFocus,
|
|
41
|
+
onKeyDown,
|
|
42
|
+
onMouseEnter,
|
|
43
|
+
role,
|
|
44
|
+
tabIndex,
|
|
43
45
|
...restProps
|
|
44
46
|
} = _ref;
|
|
45
47
|
const {
|
|
46
48
|
unregisterItem,
|
|
47
49
|
registerItem,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
currentActiveItemEl,
|
|
51
|
+
keyboardNavigationEnabled,
|
|
52
|
+
onItemFocus,
|
|
53
|
+
onItemKeyDown,
|
|
54
|
+
onItemMouseEnter,
|
|
50
55
|
wrapWithLi,
|
|
51
56
|
...menuContext
|
|
52
57
|
} = useMenuContext();
|
|
53
58
|
const actualTheme = useThemeWithUndefined(menuContext.theme ?? theme);
|
|
54
59
|
const [thisRef, setThisRef] = useState(null);
|
|
55
60
|
useEffect(() => {
|
|
61
|
+
if (!unregisterItem || !thisRef) {
|
|
62
|
+
return () => {};
|
|
63
|
+
}
|
|
64
|
+
|
|
56
65
|
return () => unregisterItem(thisRef);
|
|
57
66
|
}, [unregisterItem, thisRef]);
|
|
58
67
|
let autoTag = 'span';
|
|
@@ -67,17 +76,20 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
67
76
|
const actualIconPlacement = menuContext.iconPlacement ?? iconPlacement ?? 'left';
|
|
68
77
|
const actualMode = menuContext.mode ?? mode;
|
|
69
78
|
const actualSize = menuContext.size ?? size;
|
|
70
|
-
const actualDisableCursor = menuContext.disableCursor ?? disableCursor;
|
|
71
79
|
const resizeIcons = menuContext.resizeIcons ?? false;
|
|
80
|
+
const actualDisabled = menuContext.disabled || disabled;
|
|
72
81
|
const iconElement = icon ? /*#__PURE__*/cloneElement(icon, {
|
|
73
82
|
className: cn(icon.props.className, styles.icon, resizeIcons && styles.resizedIcon),
|
|
74
83
|
'data-render-all-sizes': true
|
|
75
84
|
}) : null;
|
|
76
|
-
const
|
|
85
|
+
const rovingTabIndex = currentActiveItemEl === thisRef ? 0 : -1;
|
|
86
|
+
const resolvedTabIndex = keyboardNavigationEnabled ? rovingTabIndex : tabIndex ?? 0;
|
|
77
87
|
|
|
78
88
|
const handleRef = r => {
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
if (r && registerItem) {
|
|
90
|
+
registerItem(r);
|
|
91
|
+
setThisRef(r);
|
|
92
|
+
}
|
|
81
93
|
|
|
82
94
|
if (typeof ref === 'function') {
|
|
83
95
|
ref(r);
|
|
@@ -87,12 +99,30 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
87
99
|
};
|
|
88
100
|
|
|
89
101
|
const handleKeyDown = e => {
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
onKeyDown?.(e);
|
|
103
|
+
|
|
104
|
+
if (e.defaultPrevented || !onItemKeyDown) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (thisRef) {
|
|
109
|
+
onItemKeyDown(e, thisRef);
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const handleFocus = e => {
|
|
114
|
+
onFocus?.(e);
|
|
115
|
+
|
|
116
|
+
if (onItemFocus && thisRef) {
|
|
117
|
+
onItemFocus(thisRef);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const handleMouseEnter = e => {
|
|
122
|
+
onMouseEnter?.(e);
|
|
92
123
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
124
|
+
if (onItemMouseEnter && thisRef) {
|
|
125
|
+
onItemMouseEnter(thisRef);
|
|
96
126
|
}
|
|
97
127
|
};
|
|
98
128
|
|
|
@@ -100,18 +130,28 @@ const MenuItemInner = (_ref, ref) => {
|
|
|
100
130
|
return /*#__PURE__*/React.createElement(Wrapper, {
|
|
101
131
|
className: cn(styles.wrapper, className, ICON_PLACEMENT_STYLES[actualIconPlacement], MODE_STYLES[actualMode], SIZE_STYLES[actualSize], THEME_STYLES[actualTheme]),
|
|
102
132
|
"data-test": 'menu-item__wrapper',
|
|
103
|
-
"data-rs-internal": 'menu__menu-item'
|
|
104
|
-
|
|
133
|
+
"data-rs-internal": 'menu__menu-item',
|
|
134
|
+
role: keyboardNavigationEnabled ? 'presentation' : undefined
|
|
135
|
+
}, /*#__PURE__*/React.createElement(Tag, { ...restProps,
|
|
136
|
+
onFocus: handleFocus,
|
|
105
137
|
onKeyDown: handleKeyDown,
|
|
138
|
+
onMouseEnter: handleMouseEnter,
|
|
106
139
|
ref: handleRef,
|
|
107
|
-
className: cn(styles.menuItem,
|
|
108
|
-
"data-test": 'menu-item',
|
|
140
|
+
className: cn(styles.menuItem, actualDisabled && styles.disabled, selected && styles.selected),
|
|
141
|
+
"data-test": restProps['data-test'] ?? 'menu-item',
|
|
109
142
|
"data-rs-internal": 'menu__menu-item__inner',
|
|
110
|
-
|
|
111
|
-
|
|
143
|
+
role: role ?? (keyboardNavigationEnabled ? 'option' : undefined),
|
|
144
|
+
"aria-selected": keyboardNavigationEnabled && selected !== undefined ? selected : restProps['aria-selected'],
|
|
145
|
+
"aria-disabled": keyboardNavigationEnabled && actualDisabled ? true : restProps['aria-disabled'],
|
|
146
|
+
tabIndex: resolvedTabIndex
|
|
112
147
|
}, iconElement, /*#__PURE__*/React.createElement("span", {
|
|
148
|
+
className: styles.contentWrapper
|
|
149
|
+
}, /*#__PURE__*/React.createElement("span", {
|
|
113
150
|
className: styles.content
|
|
114
|
-
}, children)
|
|
151
|
+
}, children), selected && /*#__PURE__*/React.createElement(CheckOutlineIcon, {
|
|
152
|
+
className: cn(styles.icon, resizeIcons && styles.resizedIcon),
|
|
153
|
+
"data-render-all-sizes": true
|
|
154
|
+
}))));
|
|
115
155
|
};
|
|
116
156
|
|
|
117
157
|
const MenuItem = /*#__PURE__*/React.forwardRef(MenuItemInner);
|
|
@@ -119,13 +159,8 @@ MenuItem.propTypes = {
|
|
|
119
159
|
size: PropTypes.oneOf(['l', 'm', 's']),
|
|
120
160
|
mode: PropTypes.oneOf(['clear', 'classic', 'rock']),
|
|
121
161
|
theme: PropTypes.oneOf(['light', 'dark']),
|
|
122
|
-
onClick: PropTypes.func,
|
|
123
162
|
disabled: PropTypes.bool,
|
|
124
|
-
disableCursor: PropTypes.bool,
|
|
125
163
|
selected: PropTypes.bool,
|
|
126
|
-
|
|
127
|
-
/** @ignore */
|
|
128
|
-
highlighted: PropTypes.bool,
|
|
129
164
|
icon: PropTypes.element,
|
|
130
165
|
iconPlacement: PropTypes.oneOf(['left', 'right']),
|
|
131
166
|
tag: PropTypes.elementType
|
|
@@ -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 {};
|