@linzjs/step-ag-grid 1.4.5 → 1.4.6

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.
Files changed (72) hide show
  1. package/dist/index.js +195 -163
  2. package/dist/index.js.map +1 -1
  3. package/dist/src/react-menu3/components/FocusableItem.d.ts +9 -1
  4. package/dist/src/react-menu3/components/Menu.d.ts +16 -2
  5. package/dist/src/react-menu3/components/MenuButton.d.ts +8 -1
  6. package/dist/src/react-menu3/components/MenuDivider.d.ts +3 -2
  7. package/dist/src/react-menu3/components/MenuGroup.d.ts +12 -2
  8. package/dist/src/react-menu3/components/MenuHeader.d.ts +4 -2
  9. package/dist/src/react-menu3/components/MenuItem.d.ts +59 -1
  10. package/dist/src/react-menu3/components/MenuList.d.ts +57 -30
  11. package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +44 -2
  12. package/dist/src/react-menu3/components/SubMenu.d.ts +110 -1
  13. package/dist/src/react-menu3/hooks/useBEM.d.ts +4 -3
  14. package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +2 -2
  15. package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
  16. package/dist/src/react-menu3/hooks/useItemState.d.ts +4 -3
  17. package/dist/src/react-menu3/hooks/useItems.d.ts +6 -4
  18. package/dist/src/react-menu3/hooks/useMenuChange.d.ts +2 -1
  19. package/dist/src/react-menu3/hooks/useMenuState.d.ts +13 -10
  20. package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +2 -10
  21. package/dist/src/react-menu3/index.d.ts +391 -0
  22. package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +10 -9
  23. package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +7 -6
  24. package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +7 -6
  25. package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +17 -19
  26. package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +18 -20
  27. package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +11 -6
  28. package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +23 -18
  29. package/dist/src/react-menu3/utils/constants.d.ts +51 -9
  30. package/dist/src/react-menu3/utils/propTypes.d.ts +1 -0
  31. package/dist/src/react-menu3/utils/utils.d.ts +19 -10
  32. package/dist/src/react-menu3/utils/withHovering.d.ts +7 -1
  33. package/dist/src/stories/components/ReactMenu.stories.d.ts +8 -0
  34. package/dist/step-ag-grid.esm.js +197 -165
  35. package/dist/step-ag-grid.esm.js.map +1 -1
  36. package/package.json +11 -11
  37. package/src/components/gridForm/GridFormDropDown.tsx +1 -1
  38. package/src/components/gridForm/GridFormMultiSelect.tsx +10 -4
  39. package/src/react-menu3/components/ControlledMenu.tsx +2 -1
  40. package/src/react-menu3/components/FocusableItem.tsx +58 -53
  41. package/src/react-menu3/components/Menu.tsx +40 -28
  42. package/src/react-menu3/components/MenuButton.tsx +30 -29
  43. package/src/react-menu3/components/MenuDivider.tsx +14 -18
  44. package/src/react-menu3/components/MenuGroup.tsx +25 -16
  45. package/src/react-menu3/components/MenuHeader.tsx +14 -18
  46. package/src/react-menu3/components/MenuItem.tsx +159 -106
  47. package/src/react-menu3/components/MenuList.tsx +104 -36
  48. package/src/react-menu3/components/MenuRadioGroup.tsx +54 -15
  49. package/src/react-menu3/components/SubMenu.tsx +307 -201
  50. package/src/react-menu3/hooks/useBEM.ts +4 -3
  51. package/src/react-menu3/hooks/useCombinedRef.ts +6 -12
  52. package/src/react-menu3/hooks/useItemEffect.ts +6 -5
  53. package/src/react-menu3/hooks/useItemState.ts +16 -12
  54. package/src/react-menu3/hooks/useItems.ts +11 -10
  55. package/src/react-menu3/hooks/useMenuChange.ts +3 -3
  56. package/src/react-menu3/hooks/useMenuState.ts +25 -7
  57. package/src/react-menu3/hooks/useMenuStateAndFocus.ts +6 -4
  58. package/src/react-menu3/index.d.ts +1 -0
  59. package/src/react-menu3/index.ts +431 -0
  60. package/src/react-menu3/positionUtils/getPositionHelpers.ts +18 -11
  61. package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +12 -5
  62. package/src/react-menu3/positionUtils/placeArrowVertical.ts +12 -5
  63. package/src/react-menu3/positionUtils/placeLeftorRight.ts +33 -17
  64. package/src/react-menu3/positionUtils/placeToporBottom.ts +34 -18
  65. package/src/react-menu3/positionUtils/positionContextMenu.ts +15 -3
  66. package/src/react-menu3/positionUtils/positionMenu.ts +21 -14
  67. package/src/react-menu3/style-utils/index.ts +10 -7
  68. package/src/react-menu3/utils/constants.ts +63 -10
  69. package/src/react-menu3/utils/propTypes.ts +3 -1
  70. package/src/react-menu3/utils/utils.ts +40 -23
  71. package/src/react-menu3/utils/withHovering.tsx +11 -6
  72. package/src/stories/components/ReactMenu.stories.tsx +37 -0
@@ -1,7 +1,5 @@
1
- // @ts-nocheck
2
1
  import { useRef, useContext, useEffect, useMemo, useImperativeHandle } from "react";
3
2
  import { createPortal } from "react-dom";
4
- import { node, func, bool, shape, oneOf, oneOfType } from "prop-types";
5
3
  import { useBEM, useCombinedRef, useMenuChange, useMenuStateAndFocus, useItemEffect } from "../hooks";
6
4
  import { MenuList } from "./MenuList";
7
5
  import {
@@ -9,9 +7,6 @@ import {
9
7
  batchedUpdates,
10
8
  commonProps,
11
9
  safeCall,
12
- stylePropTypes,
13
- uncontrolledMenuPropTypes,
14
- menuPropTypes,
15
10
  menuClass,
16
11
  subMenuClass,
17
12
  menuItemClass,
@@ -25,219 +20,330 @@ import {
25
20
  HoverActionTypes,
26
21
  FocusPositions,
27
22
  } from "../utils";
23
+ import {
24
+ BaseProps,
25
+ ClassNameProp,
26
+ Hoverable,
27
+ MenuAlign,
28
+ MenuArrowModifiers,
29
+ MenuDirection,
30
+ MenuModifiers,
31
+ MenuOverflow,
32
+ MenuPosition,
33
+ RenderProp,
34
+ UncontrolledMenuProps,
35
+ } from "../index";
36
+ import { withHoveringResultProps } from "../utils/withHovering";
28
37
 
29
- export const SubMenu = withHovering(
30
- "SubMenu",
31
- function SubMenu({
32
- "aria-label": ariaLabel,
33
- className,
34
- disabled,
35
- direction,
36
- label,
37
- openTrigger,
38
- onMenuChange,
39
- isHovering,
40
- instanceRef,
41
- itemRef,
42
- captureFocus: _1,
43
- repositionFlag: _2,
44
- itemProps = {},
45
- ...restProps
46
- }) {
47
- const settings = useContext(SettingsContext);
48
- const { rootMenuRef } = settings;
49
- const { submenuOpenDelay, submenuCloseDelay } = useContext(ItemSettingsContext);
50
- const { parentMenuRef, parentDir, overflow: parentOverflow } = useContext(MenuListContext);
51
- const { isParentOpen, isSubmenuOpen, setOpenSubmenuCount, dispatch, updateItems } = useContext(MenuListItemContext);
52
- const isPortal = parentOverflow !== "visible";
53
-
54
- const [stateProps, toggleMenu, _openMenu] = useMenuStateAndFocus(settings);
55
-
56
- const { state } = stateProps;
57
- const isDisabled = !!disabled;
58
- const isOpen = isMenuOpen(state);
59
- const containerRef = useRef(null);
60
- const timeoutId = useRef(0);
61
-
62
- const stopTimer = () => {
63
- if (timeoutId.current) {
64
- clearTimeout(timeoutId.current);
65
- timeoutId.current = 0;
66
- }
67
- };
38
+ //
39
+ // SubMenu
40
+ // ----------------------------------------------------------------------
41
+ export type SubMenuItemModifiers = Readonly<{
42
+ /**
43
+ * Indicates if the submenu is open.
44
+ */
45
+ open: boolean;
46
+ /**
47
+ * Indicates if the submenu item is being hovered and has focus.
48
+ */
49
+ hover: boolean;
50
+ /**
51
+ * Indicates if the submenu and item are disabled.
52
+ */
53
+ disabled: boolean;
54
+ }>;
68
55
 
69
- const openMenu = (...args) => {
70
- stopTimer();
71
- setHover();
72
- !isDisabled && _openMenu(...args);
73
- };
56
+ /**
57
+ * Common props for `Menu`, `SubMenu` and `ControlledMenu`
58
+ */
59
+ interface BaseMenuProps extends Omit<BaseProps, "style"> {
60
+ /**
61
+ * Can be a string or a function which receives a modifier object and returns a CSS `class` string.
62
+ */
63
+ menuClassName?: ClassNameProp<MenuModifiers>;
64
+ /**
65
+ * This prop is forwarded to the `style` prop of menu DOM element.
66
+ */
67
+ menuStyle?: React.CSSProperties;
68
+ /**
69
+ * Can be a string or a function which receives a modifier object and returns a CSS `class` string.
70
+ */
71
+ arrowClassName?: ClassNameProp<MenuArrowModifiers>;
72
+ /**
73
+ * This prop is forwarded to the `style` prop of menu arrow DOM element.
74
+ */
75
+ arrowStyle?: React.CSSProperties;
76
+ /**
77
+ * Set `true` to display an arrow pointing to its anchor element.
78
+ */
79
+ arrow?: boolean;
80
+ /**
81
+ * Set the horizontal distance (in pixels) between menu and its anchor element.
82
+ * The value can be negative.
83
+ * @default 0
84
+ */
85
+ offsetX?: number;
86
+ /**
87
+ * Set the vertical distance (in pixels) between menu and its anchor element.
88
+ * The value can be negative.
89
+ * @default 0
90
+ */
91
+ offsetY?: number;
92
+ /**
93
+ * Set alignment of menu with anchor element.
94
+ * @default 'start'
95
+ */
96
+ align?: MenuAlign;
97
+ /**
98
+ * Set direction in which menu expands against anchor element.
99
+ * @default 'bottom'
100
+ */
101
+ direction?: MenuDirection;
102
+ /**
103
+ * Set the position of menu related to its anchor element:
104
+ *
105
+ * - 'auto' menu position is adjusted to have it contained within the viewport,
106
+ * even if it will be detached from the anchor element.
107
+ * This option allows to display menu in the viewport as much as possible.
108
+ *
109
+ * - 'anchor' menu position is adjusted to have it contained within the viewport,
110
+ * but it will be kept attached to the edges of anchor element.
111
+ *
112
+ * - 'initial' menu always stays at its initial position.
113
+ * @default 'auto'
114
+ */
115
+ position?: MenuPosition;
116
+ /**
117
+ * Make the menu list scrollable or hidden when there is not enough viewport space to
118
+ * display all menu items. The prop is similar to the CSS `overflow` property.
119
+ * @default 'visible'
120
+ */
121
+ overflow?: MenuOverflow;
122
+ /**
123
+ * Set computed overflow amount down to a child `MenuGroup`.
124
+ * The `MenuGroup` should have `takeOverflow` prop set as `true` accordingly.
125
+ */
126
+ setDownOverflow?: boolean;
127
+ children?: React.ReactNode;
128
+ }
74
129
 
75
- const setHover = () => !isHovering && !isDisabled && dispatch(HoverActionTypes.SET, itemRef.current);
130
+ export interface SubMenuProps extends BaseMenuProps, Hoverable, UncontrolledMenuProps, withHoveringResultProps {
131
+ /**
132
+ * Properties of this object are spread to the submenu item DOM element.
133
+ */
134
+ itemProps?: BaseProps<SubMenuItemModifiers>;
135
+ /**
136
+ * The submenu `label` can be a `string` or JSX element, or a render function that returns one.
137
+ */
138
+ label?: RenderProp<SubMenuItemModifiers>;
139
+ /**
140
+ * - `undefined` submenu opens when the label item is hovered or clicked. This is the default behaviour.
141
+ * - 'clickOnly' submenu opens when the label item is clicked.
142
+ * - 'none' submenu doesn't open with mouse or keyboard events;
143
+ * you can call the `openMenu` function on `instanceRef` to open submenu programmatically.
144
+ */
145
+ openTrigger?: "none" | "clickOnly";
146
+ }
76
147
 
77
- const delayOpen = (delay) => {
78
- setHover();
79
- if (!openTrigger) timeoutId.current = setTimeout(() => batchedUpdates(openMenu), Math.max(delay, 0));
80
- };
148
+ export const SubMenuFr = ({
149
+ "aria-label": ariaLabel,
150
+ className,
151
+ disabled,
152
+ direction,
153
+ label,
154
+ openTrigger,
155
+ onMenuChange,
156
+ isHovering,
157
+ instanceRef,
158
+ menuItemRef,
159
+ itemProps = {},
160
+ ...restProps
161
+ }: SubMenuProps) => {
162
+ const settings = useContext(SettingsContext);
163
+ const { rootMenuRef } = settings;
164
+ const { submenuOpenDelay, submenuCloseDelay } = useContext(ItemSettingsContext);
165
+ const { parentMenuRef, parentDir, overflow: parentOverflow } = useContext(MenuListContext);
166
+ const { isParentOpen, isSubmenuOpen, setOpenSubmenuCount, dispatch, updateItems } = useContext(MenuListItemContext);
167
+ const isPortal = parentOverflow !== "visible";
81
168
 
82
- const handlePointerMove = () => {
83
- if (timeoutId.current || isOpen || isDisabled) return;
169
+ // FIXME Matt no idea what's going on here
170
+ const [stateProps, toggleMenu, _openMenu] = useMenuStateAndFocus(settings);
84
171
 
85
- if (isSubmenuOpen) {
86
- timeoutId.current = setTimeout(() => delayOpen(submenuOpenDelay - submenuCloseDelay), submenuCloseDelay);
87
- } else {
88
- delayOpen(submenuOpenDelay);
89
- }
90
- };
91
-
92
- const handlePointerLeave = () => {
93
- stopTimer();
94
- if (!isOpen) dispatch(HoverActionTypes.UNSET, itemRef.current);
95
- };
96
-
97
- const handleKeyDown = (e) => {
98
- let handled = false;
99
-
100
- switch (e.key) {
101
- // LEFT key is bubbled up from submenu items
102
- case Keys.LEFT:
103
- if (isOpen) {
104
- itemRef.current.focus();
105
- toggleMenu(false);
106
- handled = true;
107
- }
108
- break;
109
-
110
- // prevent browser from scrolling page to the right
111
- case Keys.RIGHT:
112
- if (!isOpen) handled = true;
113
- break;
114
- }
172
+ const { state } = stateProps;
173
+ const isDisabled = !!disabled;
174
+ const isOpen = isMenuOpen(state);
175
+ const containerRef = useRef(null);
176
+ const timeoutId = useRef<ReturnType<typeof setTimeout>>();
115
177
 
116
- if (handled) {
117
- e.preventDefault();
118
- e.stopPropagation();
119
- }
120
- };
178
+ const stopTimer = () => {
179
+ if (timeoutId.current) {
180
+ clearTimeout(timeoutId.current);
181
+ timeoutId.current = undefined;
182
+ }
183
+ };
121
184
 
122
- const handleItemKeyDown = (e) => {
123
- if (!isHovering) return;
185
+ const openMenu = (...args: any[]) => {
186
+ stopTimer();
187
+ setHover();
188
+ !isDisabled && _openMenu(...args);
189
+ };
124
190
 
125
- switch (e.key) {
126
- case Keys.ENTER:
127
- case Keys.SPACE:
128
- case Keys.RIGHT:
129
- openTrigger !== "none" && openMenu(FocusPositions.FIRST);
130
- break;
131
- }
132
- };
133
-
134
- useItemEffect(isDisabled, itemRef, updateItems);
135
- useMenuChange(onMenuChange, isOpen);
136
-
137
- useEffect(() => () => clearTimeout(timeoutId.current), []);
138
- useEffect(() => {
139
- // Don't set focus when parent menu is closed, otherwise focus will be lost
140
- // and onBlur event will be fired with relatedTarget setting as null.
141
- if (isHovering && isParentOpen) {
142
- itemRef.current.focus();
143
- } else {
144
- toggleMenu(false);
145
- }
146
- }, [isHovering, isParentOpen, toggleMenu, itemRef]);
191
+ const setHover = () => !isHovering && !isDisabled && dispatch(HoverActionTypes.SET, menuItemRef?.current, 0);
192
+
193
+ const delayOpen = (delay: number) => {
194
+ setHover();
195
+ if (!openTrigger) timeoutId.current = setTimeout(() => batchedUpdates(openMenu), Math.max(delay, 0));
196
+ };
197
+
198
+ const handlePointerMove = () => {
199
+ if (timeoutId.current || isOpen || isDisabled) return;
200
+
201
+ if (isSubmenuOpen) {
202
+ timeoutId.current = setTimeout(() => delayOpen(submenuOpenDelay - submenuCloseDelay), submenuCloseDelay);
203
+ } else {
204
+ delayOpen(submenuOpenDelay);
205
+ }
206
+ };
147
207
 
148
- useEffect(() => {
149
- setOpenSubmenuCount((count) => (isOpen ? count + 1 : Math.max(count - 1, 0)));
150
- }, [setOpenSubmenuCount, isOpen]);
208
+ const handlePointerLeave = () => {
209
+ stopTimer();
210
+ if (!isOpen) dispatch(HoverActionTypes.UNSET, menuItemRef?.current, 0);
211
+ };
151
212
 
152
- useImperativeHandle(instanceRef, () => ({
153
- openMenu: (...args) => {
154
- isParentOpen && openMenu(...args);
155
- },
156
- closeMenu: () => {
213
+ const handleKeyDown = (e: React.KeyboardEvent) => {
214
+ let handled = false;
215
+
216
+ switch (e.key) {
217
+ // LEFT key is bubbled up from submenu items
218
+ case Keys.LEFT:
157
219
  if (isOpen) {
158
- itemRef.current.focus();
220
+ menuItemRef?.current && menuItemRef.current.focus();
159
221
  toggleMenu(false);
222
+ handled = true;
160
223
  }
161
- },
162
- }));
163
-
164
- const modifiers = useMemo(
165
- () => ({
166
- open: isOpen,
167
- hover: isHovering,
168
- disabled: isDisabled,
169
- submenu: true,
170
- }),
171
- [isOpen, isHovering, isDisabled],
172
- );
224
+ break;
225
+
226
+ // prevent browser from scrolling page to the right
227
+ case Keys.RIGHT:
228
+ if (!isOpen) handled = true;
229
+ break;
230
+ }
173
231
 
174
- const { ref: externalItemRef, className: itemClassName, ...restItemProps } = itemProps;
232
+ if (handled) {
233
+ e.preventDefault();
234
+ e.stopPropagation();
235
+ }
236
+ };
175
237
 
176
- const mergedItemProps = mergeProps(
177
- {
178
- onPointerMove: handlePointerMove,
179
- onPointerLeave: handlePointerLeave,
180
- onKeyDown: handleItemKeyDown,
181
- onClick: () => openTrigger !== "none" && openMenu(),
182
- },
183
- restItemProps,
238
+ const handleItemKeyDown = (e: React.KeyboardEvent) => {
239
+ if (!isHovering) return;
240
+
241
+ switch (e.key) {
242
+ case Keys.ENTER:
243
+ case Keys.SPACE:
244
+ case Keys.RIGHT:
245
+ openTrigger !== "none" && openMenu(FocusPositions.FIRST);
246
+ break;
247
+ }
248
+ };
249
+
250
+ useItemEffect(isDisabled, menuItemRef, updateItems);
251
+ useMenuChange(onMenuChange, isOpen);
252
+
253
+ useEffect(() => () => clearTimeout(timeoutId.current), []);
254
+ useEffect(() => {
255
+ // Don't set focus when parent menu is closed, otherwise focus will be lost
256
+ // and onBlur event will be fired with relatedTarget setting as null.
257
+ if (isHovering && isParentOpen) {
258
+ menuItemRef?.current && menuItemRef.current.focus();
259
+ } else {
260
+ toggleMenu(false);
261
+ }
262
+ }, [isHovering, isParentOpen, toggleMenu, menuItemRef]);
263
+
264
+ useEffect(() => {
265
+ setOpenSubmenuCount((count: number) => (isOpen ? count + 1 : Math.max(count - 1, 0)));
266
+ }, [setOpenSubmenuCount, isOpen]);
267
+
268
+ useImperativeHandle(instanceRef, () => ({
269
+ openMenu: (...args) => {
270
+ isParentOpen && openMenu(...args);
271
+ },
272
+ closeMenu: () => {
273
+ if (isOpen) {
274
+ menuItemRef?.current && menuItemRef.current.focus();
275
+ toggleMenu(false);
276
+ }
277
+ },
278
+ }));
279
+
280
+ const modifiers = useMemo(
281
+ () => ({
282
+ open: isOpen,
283
+ hover: isHovering,
284
+ disabled: isDisabled,
285
+ submenu: true,
286
+ }),
287
+ [isOpen, isHovering, isDisabled],
288
+ );
289
+
290
+ const { ref: externalItemRef, className: itemClassName, ...restItemProps } = itemProps;
291
+
292
+ const mergedItemProps = mergeProps(
293
+ {
294
+ onPointerMove: handlePointerMove,
295
+ onPointerLeave: handlePointerLeave,
296
+ onKeyDown: handleItemKeyDown,
297
+ onClick: () => openTrigger !== "none" && openMenu(),
298
+ },
299
+ restItemProps,
300
+ );
301
+
302
+ const getMenuList = () => {
303
+ const menuList = (
304
+ <MenuList
305
+ {...restProps}
306
+ {...stateProps}
307
+ ariaLabel={ariaLabel || (typeof label === "string" ? label : "Submenu")}
308
+ anchorRef={menuItemRef}
309
+ containerRef={isPortal ? rootMenuRef : containerRef}
310
+ direction={direction || (parentDir === "right" || parentDir === "left" ? parentDir : "right")}
311
+ parentScrollingRef={isPortal && parentMenuRef}
312
+ isDisabled={isDisabled}
313
+ />
184
314
  );
315
+ const container = rootMenuRef?.current;
316
+ return isPortal && container ? createPortal(menuList, container) : menuList;
317
+ };
185
318
 
186
- const getMenuList = () => {
187
- const menuList = (
188
- <MenuList
189
- {...restProps}
190
- {...stateProps}
191
- ariaLabel={ariaLabel || (typeof label === "string" ? label : "Submenu")}
192
- anchorRef={itemRef}
193
- containerRef={isPortal ? rootMenuRef : containerRef}
194
- direction={direction || (parentDir === "right" || parentDir === "left" ? parentDir : "right")}
195
- parentScrollingRef={isPortal && parentMenuRef}
196
- isDisabled={isDisabled}
197
- />
198
- );
199
- const container = rootMenuRef.current;
200
- return isPortal && container ? createPortal(menuList, container) : menuList;
201
- };
202
-
203
- return (
204
- <li
205
- className={useBEM({ block: menuClass, element: subMenuClass, className })}
206
- style={{ position: "relative" }}
207
- role="presentation"
208
- ref={containerRef}
209
- onKeyDown={handleKeyDown}
319
+ return (
320
+ <li
321
+ className={useBEM({ block: menuClass, element: subMenuClass, className })}
322
+ style={{ position: "relative" }}
323
+ role="presentation"
324
+ ref={containerRef}
325
+ onKeyDown={handleKeyDown}
326
+ >
327
+ <div
328
+ role="menuitem"
329
+ aria-haspopup
330
+ aria-expanded={isOpen}
331
+ {...mergedItemProps}
332
+ {...commonProps(isDisabled, isHovering)}
333
+ ref={useCombinedRef(externalItemRef, menuItemRef)}
334
+ className={useBEM({
335
+ block: menuClass,
336
+ element: menuItemClass,
337
+ modifiers,
338
+ className: itemClassName,
339
+ })}
210
340
  >
211
- <div
212
- role="menuitem"
213
- aria-haspopup
214
- aria-expanded={isOpen}
215
- {...mergedItemProps}
216
- {...commonProps(isDisabled, isHovering)}
217
- ref={useCombinedRef(externalItemRef, itemRef)}
218
- className={useBEM({
219
- block: menuClass,
220
- element: menuItemClass,
221
- modifiers,
222
- className: itemClassName,
223
- })}
224
- >
225
- {useMemo(() => safeCall(label, modifiers), [label, modifiers])}
226
- </div>
227
-
228
- {state && getMenuList()}
229
- </li>
230
- );
231
- },
232
- );
233
-
234
- SubMenu.propTypes = {
235
- ...menuPropTypes,
236
- ...uncontrolledMenuPropTypes,
237
- disabled: bool,
238
- openTrigger: oneOf(["none", "clickOnly"]),
239
- label: oneOfType([node, func]),
240
- itemProps: shape({
241
- ...stylePropTypes(),
242
- }),
341
+ {useMemo(() => safeCall(label, modifiers), [label, modifiers])}
342
+ </div>
343
+
344
+ {state && getMenuList()}
345
+ </li>
346
+ );
243
347
  };
348
+
349
+ export const SubMenu = withHovering("SubMenu", SubMenuFr) as any as typeof SubMenuFr;
@@ -1,12 +1,13 @@
1
1
  import { useMemo } from "react";
2
+ import { ClassNameProp } from "../index";
2
3
 
3
4
  type useBemModifiers = Record<string, boolean | string | undefined>;
4
5
 
5
6
  interface useBemProps {
6
7
  block: string;
7
- element: string;
8
- modifiers: useBemModifiers;
9
- className: string | ((modifiers: useBemModifiers) => string | undefined);
8
+ element?: string;
9
+ modifiers?: useBemModifiers;
10
+ className?: ClassNameProp<any>; // FIXME Matt any?
10
11
  }
11
12
 
12
13
  // Generate className following BEM methodology: http://getbem.com/naming/
@@ -1,12 +1,9 @@
1
- import { Ref, MutableRefObject, useMemo } from "react";
1
+ import { useMemo, LegacyRef, ForwardedRef } from "react";
2
2
 
3
3
  // Adapted from material-ui
4
4
  // https://github.com/mui-org/material-ui/blob/f996027d00e7e4bff3fc040786c1706f9c6c3f82/packages/material-ui-utils/src/useForkRef.ts
5
5
 
6
- const setRef = <T>(
7
- ref: MutableRefObject<T | null> | ((instance: T | null) => void) | null | undefined,
8
- instance: T | null,
9
- ) => {
6
+ const setRef = <T>(ref: ForwardedRef<T> | undefined, instance: T | null) => {
10
7
  if (typeof ref === "function") {
11
8
  ref(instance);
12
9
  } else if (ref) {
@@ -15,14 +12,11 @@ const setRef = <T>(
15
12
  };
16
13
 
17
14
  export const useCombinedRef = <Instance>(
18
- refA: Ref<Instance> | null | undefined,
19
- refB: Ref<Instance> | null | undefined,
20
- ): Ref<Instance> | null | undefined => {
15
+ refA: ForwardedRef<Instance> | undefined,
16
+ refB: ForwardedRef<Instance> | undefined,
17
+ ): LegacyRef<Instance> => {
21
18
  return useMemo(() => {
22
- if (!refA) return refB;
23
- if (!refB) return refA;
24
-
25
- return (instance) => {
19
+ return (instance: any) => {
26
20
  setRef(refA, instance);
27
21
  setRef(refB, instance);
28
22
  };
@@ -2,21 +2,22 @@ import { MutableRefObject } from "react";
2
2
  import { useLayoutEffect } from "./useIsomorphicLayoutEffect";
3
3
 
4
4
  export const useItemEffect = (
5
- isDisabled: boolean,
6
- itemRef: MutableRefObject<any>,
5
+ isDisabled: boolean | undefined,
6
+ menuItemRef: MutableRefObject<any> | undefined,
7
7
  updateItems: (item: any, isMounted?: boolean) => void,
8
8
  ) => {
9
9
  useLayoutEffect(() => {
10
+ if (!menuItemRef) return;
10
11
  if (process.env.NODE_ENV !== "production" && !updateItems) {
11
12
  throw new Error(
12
- `[React-Menu] This menu item or submenu should be rendered under a menu: ${itemRef.current.outerHTML}`,
13
+ `[React-Menu] This menu item or submenu should be rendered under a menu: ${menuItemRef.current.outerHTML}`,
13
14
  );
14
15
  }
15
16
  if (isDisabled) return;
16
- const item = itemRef.current;
17
+ const item = menuItemRef.current;
17
18
  updateItems(item, true);
18
19
  return () => {
19
20
  updateItems(item);
20
21
  };
21
- }, [isDisabled, itemRef, updateItems]);
22
+ }, [isDisabled, menuItemRef, updateItems]);
22
23
  };