@ringcentral/spring-ui 1.9.2 → 1.9.3

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.
@@ -8,7 +8,7 @@ const useNestedChildMenu = (props) => {
8
8
  const { open, closeMenu, id } = props;
9
9
  const context = useNestedMenuContext();
10
10
  const { registOpenedSubMenu } = context ?? {};
11
- const closeMenuMemo = useEventCallback(() => closeMenu());
11
+ const closeMenuMemo = useEventCallback((options) => closeMenu(options));
12
12
  useEffect(() => {
13
13
  if (open) {
14
14
  return registOpenedSubMenu?.({
package/SubMenu.js CHANGED
@@ -6,7 +6,7 @@ import { Popper } from './Popper.js';
6
6
  import { CaretRightMd } from '@ringcentral/spring-icon';
7
7
  import { useThemeProps } from '@ringcentral/spring-theme';
8
8
  import { I as Icon } from './chunks/Icon.js';
9
- import { M as MenuItem } from './chunks/useMenuItemSelect.js';
9
+ import { S as SubMenuTriggerNestedIdContext, M as MenuItem } from './chunks/useMenuItemSelect.js';
10
10
  import 'tabbable';
11
11
  import './chunks/useListNavigation.js';
12
12
  import './chunks/Menu.js';
@@ -49,7 +49,9 @@ const SubMenu = forwardRef((inProps, ref) => {
49
49
  const itemRef = useRef(null);
50
50
  const handleRef = useForkRef(itemRef, ref);
51
51
  const open = Boolean(anchor);
52
- const closeSubMenu = () => {
52
+ const restoreFocusOnCloseRef = useRef(false);
53
+ const closeSubMenu = (options) => {
54
+ restoreFocusOnCloseRef.current = options?.restoreFocus === true;
53
55
  setAnchor(null);
54
56
  };
55
57
  const { hover: anchorHover, hoverHandlers: anchorHoverHandlers } = useHover({
@@ -74,38 +76,28 @@ const SubMenu = forwardRef((inProps, ref) => {
74
76
  useNestedMenuItem({ hovered: anchorHover, id });
75
77
  useNestedChildMenu({
76
78
  open,
77
- closeMenu: () => {
78
- closeSubMenu();
79
- },
79
+ closeMenu: (options) => closeSubMenu(options),
80
80
  id,
81
81
  });
82
82
  const shouldKeepMenu = (() => {
83
83
  if (!open)
84
84
  return false;
85
- if (open && !menuMounted)
85
+ if (!menuMounted)
86
86
  return true;
87
- let shouldKeepMenu = false;
88
- if (focusVisibleWithin) {
89
- shouldKeepMenu = true;
90
- }
91
- if ((!menuHover && menuHoverEverRef.current) ||
92
- (!anchorHover && anchorHoverEverRef.current)) {
93
- shouldKeepMenu = false;
94
- }
95
- if (menuHover || anchorHover) {
96
- shouldKeepMenu = true;
97
- }
98
- return shouldKeepMenu;
87
+ if (focusVisibleWithin)
88
+ return true;
89
+ return menuHover || anchorHover;
99
90
  })();
100
91
  useEffect(() => {
101
92
  if (!shouldKeepMenu) {
102
93
  closeSubMenu();
103
94
  }
104
- return undefined;
105
95
  }, [shouldKeepMenu]);
106
96
  useOnLayoutReRender(() => {
97
+ const restoreFocus = restoreFocusOnCloseRef.current;
107
98
  if (!open) {
108
- itemRef.current?.focus();
99
+ restoreFocus && itemRef.current?.focus();
100
+ restoreFocusOnCloseRef.current = false;
109
101
  }
110
102
  }, [open]);
111
103
  useEffect(() => {
@@ -115,21 +107,19 @@ const SubMenu = forwardRef((inProps, ref) => {
115
107
  anchorHoverEverRef.current = false;
116
108
  }
117
109
  }, [open]);
118
- return (jsxs(Fragment, { children: [jsxs(MenuItem, { autoClose: false, ...rest, onKeyDown: (e) => {
119
- onKeyDownProp?.(e);
120
- if (e.key === 'ArrowRight') {
121
- setAnchor(e.currentTarget);
122
- }
123
- }, ...anchorHoverHandlers, ref: handleRef, children: [typeof itemContent === 'string' ? (jsx(MenuItemText, { children: itemContent })) : (itemContent), jsx(Icon, { symbol: CaretRightMd })] }), open && (jsx(PopperMenu, { anchorEl: anchor, placement: "right-start", offset: -4, whileElementsMounted: () => {
110
+ return (jsxs(Fragment, { children: [jsx(SubMenuTriggerNestedIdContext.Provider, { value: id, children: jsxs(MenuItem, { autoClose: false, ...rest, onKeyDown: (e) => {
111
+ onKeyDownProp?.(e);
112
+ if (e.key === 'ArrowRight') {
113
+ setAnchor(e.currentTarget);
114
+ }
115
+ }, ...anchorHoverHandlers, ref: handleRef, children: [typeof itemContent === 'string' ? (jsx(MenuItemText, { children: itemContent })) : (itemContent), jsx(Icon, { symbol: CaretRightMd })] }) }), open && (jsx(PopperMenu, { anchorEl: anchor, placement: "right-start", offset: -4, whileElementsMounted: () => {
124
116
  setMenuMounted(true);
125
117
  return () => { };
126
118
  }, onKeyDown: (e) => {
127
119
  if ((e.key === 'ArrowLeft' || e.key === 'Escape') &&
128
120
  e.currentTarget.contains(e.target)) {
129
- if (e.key === 'Escape') {
130
- e.stopPropagation();
131
- }
132
- closeSubMenu();
121
+ e.stopPropagation();
122
+ closeSubMenu({ restoreFocus: true });
133
123
  }
134
124
  }, ...menuHoverHandlers, ...focusVisibleHandlers, children: children }))] }));
135
125
  });
@@ -15,6 +15,8 @@ const MenuListContext = createContext({
15
15
  });
16
16
  const useMenuListContext = () => useContext(MenuListContext);
17
17
 
18
+ const SubMenuTriggerNestedIdContext = createContext(null);
19
+
18
20
  const MenuItemSelectContext = createContext(null);
19
21
  const useMenuItemSelectContext = () => useContext(MenuItemSelectContext);
20
22
 
@@ -128,7 +130,9 @@ const MenuItem = forwardRef((inProps, ref) => {
128
130
  const selectMode = selectContextValue
129
131
  ? selectContextValue.selectMode
130
132
  : 'single';
131
- const id = useId();
133
+ const subMenuTriggerNestedId = useContext(SubMenuTriggerNestedIdContext);
134
+ const generatedId = useId();
135
+ const id = subMenuTriggerNestedId ?? generatedId;
132
136
  const { hover, hoverHandlers } = useHover({ onMouseEnter, onMouseLeave });
133
137
  useNestedMenuItem({ hovered: hover, id });
134
138
  useLayoutEffect(() => {
@@ -236,4 +240,4 @@ const useMenuItemSelect = (props) => {
236
240
  };
237
241
  };
238
242
 
239
- export { Action as A, MenuItem as M, MenuItemSelectContext as a, useMenuItem as b, useMenuItemSelect as c, useVirtualizedMenuItem as d, MenuListContext as e, useMenuListContext as f, useMenuItemSelectContext as u };
243
+ export { Action as A, MenuItem as M, SubMenuTriggerNestedIdContext as S, MenuItemSelectContext as a, useMenuItem as b, useMenuItemSelect as c, useVirtualizedMenuItem as d, MenuListContext as e, useMenuListContext as f, useMenuItemSelectContext as u };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ringcentral/spring-ui",
3
- "version": "1.9.2",
3
+ "version": "1.9.3",
4
4
  "author": "RingCentral",
5
5
  "description": "A comprehensive React component library built with Tailwind CSS, featuring production-ready components",
6
6
  "main": "./index.js",
@@ -15,9 +15,9 @@
15
15
  "@floating-ui/react-dom": "2.1.1",
16
16
  "@juggle/resize-observer": "3.4.0",
17
17
  "@mui/base": "5.0.0-beta.40",
18
- "@ringcentral/spring-base": "^1.9.2",
19
- "@ringcentral/spring-icon": "^1.9.2",
20
- "@ringcentral/spring-theme": "^1.9.2",
18
+ "@ringcentral/spring-base": "^1.9.3",
19
+ "@ringcentral/spring-icon": "^1.9.3",
20
+ "@ringcentral/spring-theme": "^1.9.3",
21
21
  "@types/lodash": "^4.14.182",
22
22
  "@use-gesture/react": "10.3.1",
23
23
  "clsx": "^1.2.1",
@@ -1,7 +1,10 @@
1
1
  /// <reference types="react" />
2
+ export declare type CloseSubMenuOptions = {
3
+ restoreFocus?: boolean;
4
+ };
2
5
  export declare type SubMenuItemSymbol = {
3
6
  anchorId: string;
4
- closeSubMenu: () => void;
7
+ closeSubMenu: (options?: CloseSubMenuOptions) => void;
5
8
  };
6
9
  export declare type NestedMenuContextValue = {
7
10
  registHoveredItem: (menuItemId: string) => void;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare const SubMenuTriggerNestedIdContext: import("react").Context<string | null>;
@@ -1,6 +1,7 @@
1
+ import { CloseSubMenuOptions } from './NestedMenuContext';
1
2
  export declare type UseNestedChildMenuProps = {
2
3
  open: boolean;
3
4
  id: string;
4
- closeMenu: () => void;
5
+ closeMenu: (options?: CloseSubMenuOptions) => void;
5
6
  };
6
7
  export declare const useNestedChildMenu: (props: UseNestedChildMenuProps) => void;