@linzjs/step-ag-grid 1.4.5 → 1.4.7
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/dist/index.d.ts +1 -0
- package/dist/index.js +284 -232
- package/dist/index.js.map +1 -1
- package/dist/src/components/GridCell.d.ts +4 -3
- package/dist/src/components/gridRender/GridRenderGenericCell.d.ts +8 -5
- package/dist/src/react-menu3/components/ControlledMenu.d.ts +8 -2
- package/dist/src/react-menu3/components/FocusableItem.d.ts +8 -0
- package/dist/src/react-menu3/components/Menu.d.ts +16 -2
- package/dist/src/react-menu3/components/MenuButton.d.ts +8 -1
- package/dist/src/react-menu3/components/MenuDivider.d.ts +2 -1
- package/dist/src/react-menu3/components/MenuGroup.d.ts +12 -2
- package/dist/src/react-menu3/components/MenuHeader.d.ts +4 -2
- package/dist/src/react-menu3/components/MenuItem.d.ts +56 -0
- package/dist/src/react-menu3/components/MenuList.d.ts +2 -29
- package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +44 -2
- package/dist/src/react-menu3/components/SubMenu.d.ts +109 -0
- package/dist/src/react-menu3/hooks/useBEM.d.ts +4 -3
- package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +2 -2
- package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useItemState.d.ts +4 -3
- package/dist/src/react-menu3/hooks/useItems.d.ts +6 -4
- package/dist/src/react-menu3/hooks/useMenuChange.d.ts +2 -1
- package/dist/src/react-menu3/hooks/useMenuState.d.ts +13 -10
- package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +2 -10
- package/dist/src/react-menu3/index.d.ts +1 -0
- package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +10 -9
- package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +7 -6
- package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +7 -6
- package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +17 -19
- package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +18 -20
- package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +11 -6
- package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +23 -18
- package/dist/src/react-menu3/types.d.ts +389 -0
- package/dist/src/react-menu3/utils/constants.d.ts +58 -9
- package/dist/src/react-menu3/utils/index.d.ts +0 -1
- package/dist/src/react-menu3/utils/{propTypes.d.ts → propTypes2.d.ts} +1 -0
- package/dist/src/react-menu3/utils/utils.d.ts +20 -11
- package/dist/src/react-menu3/utils/withHovering.d.ts +7 -1
- package/dist/src/stories/components/ReactMenu.stories.d.ts +8 -0
- package/dist/step-ag-grid.esm.js +276 -235
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +11 -11
- package/src/components/GridCell.tsx +6 -3
- package/src/components/GridPopoverHook.tsx +1 -1
- package/src/components/gridForm/GridFormDropDown.tsx +1 -1
- package/src/components/gridForm/GridFormMultiSelect.tsx +36 -17
- package/src/components/gridRender/GridRenderGenericCell.tsx +11 -7
- package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +14 -2
- package/src/contexts/GridContextProvider.tsx +3 -2
- package/src/react-menu3/components/ControlledMenu.tsx +40 -45
- package/src/react-menu3/components/FocusableItem.tsx +58 -53
- package/src/react-menu3/components/Menu.tsx +40 -28
- package/src/react-menu3/components/MenuButton.tsx +30 -29
- package/src/react-menu3/components/MenuDivider.tsx +14 -18
- package/src/react-menu3/components/MenuGroup.tsx +25 -16
- package/src/react-menu3/components/MenuHeader.tsx +14 -18
- package/src/react-menu3/components/MenuItem.tsx +158 -106
- package/src/react-menu3/components/MenuList.tsx +61 -36
- package/src/react-menu3/components/MenuRadioGroup.tsx +54 -15
- package/src/react-menu3/components/SubMenu.tsx +317 -202
- package/src/react-menu3/hooks/useBEM.ts +4 -3
- package/src/react-menu3/hooks/useCombinedRef.ts +6 -12
- package/src/react-menu3/hooks/useItemEffect.ts +6 -5
- package/src/react-menu3/hooks/useItemState.ts +16 -12
- package/src/react-menu3/hooks/useItems.ts +11 -10
- package/src/react-menu3/hooks/useMenuChange.ts +3 -3
- package/src/react-menu3/hooks/useMenuState.ts +25 -7
- package/src/react-menu3/hooks/useMenuStateAndFocus.ts +6 -4
- package/src/react-menu3/index.ts +1 -0
- package/src/react-menu3/positionUtils/getPositionHelpers.ts +19 -12
- package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +12 -5
- package/src/react-menu3/positionUtils/placeArrowVertical.ts +12 -5
- package/src/react-menu3/positionUtils/placeLeftorRight.ts +33 -17
- package/src/react-menu3/positionUtils/placeToporBottom.ts +34 -18
- package/src/react-menu3/positionUtils/positionContextMenu.ts +15 -3
- package/src/react-menu3/positionUtils/positionMenu.ts +21 -14
- package/src/react-menu3/style-utils/index.ts +10 -7
- package/src/react-menu3/{index.d.ts → types.ts} +106 -358
- package/src/react-menu3/utils/constants.ts +82 -10
- package/src/react-menu3/utils/index.ts +1 -1
- package/src/react-menu3/utils/{propTypes.ts → propTypes2.ts} +3 -1
- package/src/react-menu3/utils/utils.ts +41 -24
- package/src/react-menu3/utils/withHovering.tsx +11 -6
- package/src/stories/components/GridReadOnly.stories.tsx +3 -4
- package/src/stories/components/ReactMenu.stories.tsx +37 -0
|
@@ -1,43 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
cloneElement,
|
|
3
|
+
Fragment,
|
|
4
|
+
forwardRef,
|
|
5
|
+
useRef,
|
|
6
|
+
useCallback,
|
|
7
|
+
useImperativeHandle,
|
|
8
|
+
ReactElement,
|
|
9
|
+
ForwardedRef,
|
|
10
|
+
} from "react";
|
|
4
11
|
import { ControlledMenu } from "./ControlledMenu";
|
|
5
12
|
import { useMenuChange, useMenuStateAndFocus, useCombinedRef } from "../hooks";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
mergeProps,
|
|
9
|
-
safeCall,
|
|
10
|
-
isMenuOpen,
|
|
11
|
-
uncontrolledMenuPropTypes,
|
|
12
|
-
rootMenuPropTypes,
|
|
13
|
-
Keys,
|
|
14
|
-
FocusPositions,
|
|
15
|
-
} from "../utils";
|
|
13
|
+
import { getName, mergeProps, safeCall, isMenuOpen, Keys, FocusPositions } from "../utils";
|
|
14
|
+
import { MenuButtonModifiers, RenderProp, RootMenuProps, UncontrolledMenuProps } from "../types";
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
//
|
|
17
|
+
// Menu
|
|
18
|
+
// ----------------------------------------------------------------------
|
|
19
|
+
export interface MenuProps extends RootMenuProps, UncontrolledMenuProps {
|
|
20
|
+
/**
|
|
21
|
+
* Can be a `MenuButton`, a `button` element, or a React component.
|
|
22
|
+
* It also can be a render function that returns one.
|
|
23
|
+
*
|
|
24
|
+
* If a React component is provided, it needs to implement the following contracts:
|
|
25
|
+
* - Accepts a `ref` prop that is forwarded to an element to which menu will be positioned.
|
|
26
|
+
* The element should be able to receive focus.
|
|
27
|
+
* - Accepts `onClick` and `onKeyDown` event props.
|
|
28
|
+
*/
|
|
29
|
+
menuButton: RenderProp<MenuButtonModifiers, ReactElement>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function MenuFr(
|
|
33
|
+
{ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange, ...restProps }: MenuProps,
|
|
34
|
+
externalRef: ForwardedRef<any>, // FIXME Matt correct type?
|
|
20
35
|
) {
|
|
21
36
|
const [stateProps, toggleMenu, openMenu] = useMenuStateAndFocus(restProps);
|
|
22
37
|
const isOpen = isMenuOpen(stateProps.state);
|
|
23
38
|
const skipOpen = useRef(false);
|
|
24
|
-
const buttonRef = useRef(null);
|
|
39
|
+
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
25
40
|
|
|
26
41
|
const handleClose = useCallback(
|
|
27
42
|
(e) => {
|
|
28
43
|
toggleMenu(false);
|
|
29
|
-
if (e.key) buttonRef.current.focus();
|
|
44
|
+
if (e.key) buttonRef.current && buttonRef.current.focus();
|
|
30
45
|
},
|
|
31
46
|
[toggleMenu],
|
|
32
47
|
);
|
|
33
48
|
|
|
34
|
-
const onClick = (e) => {
|
|
49
|
+
const onClick = (e: MouseEvent) => {
|
|
35
50
|
if (skipOpen.current) return;
|
|
36
51
|
// Focus (hover) the first menu item when onClick event is trigger by keyboard
|
|
37
52
|
openMenu(e.detail === 0 ? FocusPositions.FIRST : undefined);
|
|
38
53
|
};
|
|
39
54
|
|
|
40
|
-
const onKeyDown = (e) => {
|
|
55
|
+
const onKeyDown = (e: KeyboardEvent) => {
|
|
41
56
|
switch (e.key) {
|
|
42
57
|
case Keys.UP:
|
|
43
58
|
openMenu(FocusPositions.LAST);
|
|
@@ -54,12 +69,14 @@ export const Menu = forwardRef(function Menu(
|
|
|
54
69
|
e.preventDefault();
|
|
55
70
|
};
|
|
56
71
|
|
|
57
|
-
|
|
72
|
+
// FIXME erk! button seems to be many types
|
|
73
|
+
const button: any = safeCall(menuButton, { open: isOpen });
|
|
58
74
|
if (!button || !button.type) throw new Error("Menu requires a menuButton prop.");
|
|
59
75
|
|
|
60
76
|
const buttonProps = {
|
|
61
77
|
ref: useCombinedRef(button.ref, buttonRef),
|
|
62
78
|
...mergeProps({ onClick, onKeyDown }, button.props),
|
|
79
|
+
isOpen: false,
|
|
63
80
|
};
|
|
64
81
|
if (getName(button.type) === "MenuButton") {
|
|
65
82
|
buttonProps.isOpen = isOpen;
|
|
@@ -87,10 +104,5 @@ export const Menu = forwardRef(function Menu(
|
|
|
87
104
|
/>
|
|
88
105
|
</Fragment>
|
|
89
106
|
);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
Menu.propTypes = {
|
|
93
|
-
...rootMenuPropTypes,
|
|
94
|
-
...uncontrolledMenuPropTypes,
|
|
95
|
-
menuButton: oneOfType([element, func]).isRequired,
|
|
96
|
-
};
|
|
107
|
+
}
|
|
108
|
+
export const Menu = forwardRef(MenuFr);
|
|
@@ -1,33 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
import { forwardRef, useMemo } from "react";
|
|
3
|
-
import { bool } from "prop-types";
|
|
1
|
+
import { forwardRef, LegacyRef, ReactNode, useMemo } from "react";
|
|
4
2
|
import { useBEM } from "../hooks";
|
|
5
|
-
import {
|
|
3
|
+
import { menuButtonClass } from "../utils";
|
|
4
|
+
import { BaseProps, MenuButtonModifiers } from "../types";
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
|
|
6
|
+
export interface MenuButtonProps extends BaseProps<MenuButtonModifiers> {
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
children?: ReactNode;
|
|
11
9
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
aria-expanded={isOpen}
|
|
16
|
-
aria-disabled={disabled || undefined}
|
|
17
|
-
type="button"
|
|
18
|
-
disabled={disabled}
|
|
19
|
-
{...restProps}
|
|
20
|
-
ref={ref}
|
|
21
|
-
className={useBEM({ block: menuButtonClass, modifiers, className })}
|
|
22
|
-
>
|
|
23
|
-
{children}
|
|
24
|
-
</button>
|
|
25
|
-
);
|
|
26
|
-
}),
|
|
27
|
-
);
|
|
10
|
+
// FIXME Matt added, seems to be an internal thing
|
|
11
|
+
isOpen?: boolean;
|
|
12
|
+
}
|
|
28
13
|
|
|
29
|
-
MenuButton
|
|
30
|
-
...
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
14
|
+
export const MenuButton = forwardRef(function MenuButton(
|
|
15
|
+
{ className, isOpen, disabled, children, ...restProps }: MenuButtonProps,
|
|
16
|
+
ref: LegacyRef<HTMLButtonElement>,
|
|
17
|
+
) {
|
|
18
|
+
const modifiers = useMemo(() => ({ open: isOpen }), [isOpen]);
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<button
|
|
22
|
+
aria-haspopup
|
|
23
|
+
aria-expanded={isOpen}
|
|
24
|
+
aria-disabled={disabled || undefined}
|
|
25
|
+
type="button"
|
|
26
|
+
disabled={disabled}
|
|
27
|
+
{...restProps}
|
|
28
|
+
ref={ref}
|
|
29
|
+
className={useBEM({ block: menuButtonClass, modifiers, className })}
|
|
30
|
+
>
|
|
31
|
+
{children}
|
|
32
|
+
</button>
|
|
33
|
+
);
|
|
34
|
+
});
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import { memo, forwardRef } from "react";
|
|
1
|
+
import { memo, forwardRef, LegacyRef } from "react";
|
|
3
2
|
import { useBEM } from "../hooks";
|
|
4
|
-
import { menuClass, menuDividerClass
|
|
3
|
+
import { menuClass, menuDividerClass } from "../utils";
|
|
4
|
+
import { BaseProps } from "../types";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
);
|
|
16
|
-
}),
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
MenuDivider.propTypes = {
|
|
20
|
-
...stylePropTypes(),
|
|
6
|
+
const MenuDividerFr = ({ className, ...restProps }: BaseProps, externalRef: LegacyRef<HTMLLIElement>) => {
|
|
7
|
+
return (
|
|
8
|
+
<li
|
|
9
|
+
role="separator"
|
|
10
|
+
{...restProps}
|
|
11
|
+
ref={externalRef}
|
|
12
|
+
className={useBEM({ block: menuClass, element: menuDividerClass, className })}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
21
15
|
};
|
|
16
|
+
|
|
17
|
+
export const MenuDivider = memo(forwardRef(MenuDividerFr));
|
|
@@ -1,38 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
import { forwardRef, useContext, useRef, useState } from "react";
|
|
3
|
-
import { bool } from "prop-types";
|
|
1
|
+
import { ForwardedRef, forwardRef, ReactNode, useContext, useRef, useState } from "react";
|
|
4
2
|
import { useBEM, useLayoutEffect, useCombinedRef } from "../hooks";
|
|
5
|
-
import { menuClass, menuGroupClass,
|
|
3
|
+
import { menuClass, menuGroupClass, MenuListContext } from "../utils";
|
|
4
|
+
import { BaseProps, MenuOverflow } from "../types";
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
export interface MenuGroupProps extends BaseProps {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
/**
|
|
9
|
+
* Set `true` to apply overflow of the parent menu to the group.
|
|
10
|
+
* Only one `MenuGroup` in a menu should set this prop as `true`.
|
|
11
|
+
*/
|
|
12
|
+
takeOverflow?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const MenuGroupFr = (
|
|
16
|
+
{ className, style, takeOverflow, ...restProps }: MenuGroupProps,
|
|
17
|
+
externalRef: ForwardedRef<HTMLDivElement>,
|
|
18
|
+
) => {
|
|
19
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
20
|
+
const [overflowStyle, setOverflowStyle] = useState<{ maxHeight?: number; overflow?: MenuOverflow }>();
|
|
10
21
|
const { overflow, overflowAmt } = useContext(MenuListContext);
|
|
11
22
|
|
|
12
23
|
useLayoutEffect(() => {
|
|
13
24
|
let maxHeight;
|
|
14
|
-
if (takeOverflow && overflowAmt >= 0) {
|
|
25
|
+
if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
|
|
26
|
+
// FIXME Matt added && ref.current
|
|
15
27
|
maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
|
|
16
28
|
if (maxHeight < 0) maxHeight = 0;
|
|
17
29
|
}
|
|
18
|
-
setOverflowStyle(maxHeight >= 0 ? { maxHeight, overflow } : undefined);
|
|
30
|
+
setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
|
|
19
31
|
}, [takeOverflow, overflow, overflowAmt]);
|
|
20
32
|
|
|
21
33
|
useLayoutEffect(() => {
|
|
22
|
-
if (overflowStyle) ref.current.scrollTop = 0;
|
|
34
|
+
if (overflowStyle && ref.current) ref.current.scrollTop = 0;
|
|
23
35
|
}, [overflowStyle]);
|
|
24
36
|
|
|
25
37
|
return (
|
|
26
38
|
<div
|
|
27
39
|
{...restProps}
|
|
28
|
-
ref={useCombinedRef(externalRef, ref)}
|
|
40
|
+
ref={useCombinedRef(externalRef, ref)} // TODO wierd refs
|
|
29
41
|
className={useBEM({ block: menuClass, element: menuGroupClass, className })}
|
|
30
42
|
style={{ ...style, ...overflowStyle }}
|
|
31
43
|
/>
|
|
32
44
|
);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
MenuGroup.propTypes = {
|
|
36
|
-
...stylePropTypes(),
|
|
37
|
-
takeOverflow: bool,
|
|
38
45
|
};
|
|
46
|
+
|
|
47
|
+
export const MenuGroup = forwardRef(MenuGroupFr);
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
import { memo, forwardRef } from "react";
|
|
1
|
+
import { memo, forwardRef, ForwardedRef } from "react";
|
|
3
2
|
import { useBEM } from "../hooks";
|
|
4
|
-
import { menuClass, menuHeaderClass
|
|
3
|
+
import { menuClass, menuHeaderClass } from "../utils";
|
|
4
|
+
import { BaseProps } from "../types";
|
|
5
5
|
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
);
|
|
16
|
-
}),
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
MenuHeader.propTypes = {
|
|
20
|
-
...stylePropTypes(),
|
|
6
|
+
export const MenuHeaderFr = ({ className, ...restProps }: BaseProps, externalRef: ForwardedRef<HTMLLIElement>) => {
|
|
7
|
+
return (
|
|
8
|
+
<li
|
|
9
|
+
role="presentation"
|
|
10
|
+
{...restProps}
|
|
11
|
+
ref={externalRef}
|
|
12
|
+
className={useBEM({ block: menuClass, element: menuHeaderClass, className })}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
21
15
|
};
|
|
16
|
+
|
|
17
|
+
export const MenuHeader = memo(forwardRef(MenuHeaderFr));
|
|
@@ -1,130 +1,182 @@
|
|
|
1
|
-
|
|
2
|
-
import { useContext, useMemo } from "react";
|
|
3
|
-
import { any, string, bool, func, node, oneOf, oneOfType } from "prop-types";
|
|
1
|
+
import { Ref, useContext, useMemo } from "react";
|
|
4
2
|
import { useBEM, useItemState, useCombinedRef } from "../hooks";
|
|
5
3
|
import {
|
|
6
4
|
mergeProps,
|
|
7
5
|
commonProps,
|
|
8
6
|
safeCall,
|
|
9
|
-
stylePropTypes,
|
|
10
7
|
menuClass,
|
|
11
8
|
menuItemClass,
|
|
12
9
|
withHovering,
|
|
13
10
|
EventHandlersContext,
|
|
14
11
|
RadioGroupContext,
|
|
15
12
|
Keys,
|
|
13
|
+
RMEvent,
|
|
16
14
|
} from "../utils";
|
|
15
|
+
import { BaseProps, ClickEvent, EventHandler, Hoverable, MenuItemTypeProp, RenderProp } from "../types";
|
|
16
|
+
import { withHoveringResultProps } from "../utils/withHovering";
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
18
|
+
//
|
|
19
|
+
// MenuItem
|
|
20
|
+
// ----------------------------------------------------------------------
|
|
21
|
+
export type MenuItemModifiers = Readonly<{
|
|
22
|
+
/**
|
|
23
|
+
* 'radio' for radio item, 'checkbox' for checkbox item, or `undefined` for other items.
|
|
24
|
+
*/
|
|
25
|
+
type?: MenuItemTypeProp;
|
|
26
|
+
/**
|
|
27
|
+
* Indicates if the menu item is disabled.
|
|
28
|
+
*/
|
|
29
|
+
disabled: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Indicates if the menu item is being hovered and has focus.
|
|
32
|
+
*/
|
|
33
|
+
hover: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Indicates if the menu item is checked when it's a radio or checkbox item.
|
|
36
|
+
*/
|
|
37
|
+
checked: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Indicates if the menu item has a URL link.
|
|
40
|
+
*/
|
|
41
|
+
anchor: boolean;
|
|
42
|
+
}>;
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
export interface MenuItemProps extends Omit<BaseProps<MenuItemModifiers>, "onClick">, Hoverable {
|
|
45
|
+
/**
|
|
46
|
+
* Any value provided to this prop will be available in the event object of click events.
|
|
47
|
+
*
|
|
48
|
+
* It's useful for helping identify which menu item is clicked when you
|
|
49
|
+
* listen on `onItemClick` event on root menu component.
|
|
50
|
+
*/
|
|
51
|
+
value?: any;
|
|
52
|
+
/**
|
|
53
|
+
* If provided, menu item renders an HTML `<a>` element with this `href` attribute.
|
|
54
|
+
*/
|
|
55
|
+
href?: string;
|
|
56
|
+
rel?: string;
|
|
57
|
+
target?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Set this prop to make the item a checkbox or radio menu item.
|
|
60
|
+
*/
|
|
61
|
+
type?: MenuItemTypeProp;
|
|
62
|
+
/**
|
|
63
|
+
* Set `true` if a checkbox menu item is checked.
|
|
64
|
+
*
|
|
65
|
+
* *Please note radio menu item doesn't use this prop.*
|
|
66
|
+
*/
|
|
67
|
+
checked?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Event fired when the menu item is clicked.
|
|
70
|
+
*/
|
|
71
|
+
onClick?: EventHandler<ClickEvent>;
|
|
72
|
+
/**
|
|
73
|
+
* Any valid React node or a render function that returns one.
|
|
74
|
+
*/
|
|
75
|
+
children?: RenderProp<MenuItemModifiers>;
|
|
76
|
+
}
|
|
49
77
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
78
|
+
const MenuItemFr = ({
|
|
79
|
+
className,
|
|
80
|
+
value,
|
|
81
|
+
href,
|
|
82
|
+
type,
|
|
83
|
+
checked,
|
|
84
|
+
disabled,
|
|
85
|
+
children,
|
|
86
|
+
onClick,
|
|
87
|
+
isHovering,
|
|
88
|
+
menuItemRef,
|
|
89
|
+
externalRef,
|
|
90
|
+
...restProps
|
|
91
|
+
}: MenuItemProps & withHoveringResultProps) => {
|
|
92
|
+
const isDisabled = !!disabled;
|
|
93
|
+
const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
|
|
94
|
+
const eventHandlers = useContext(EventHandlersContext);
|
|
95
|
+
const radioGroup = useContext(RadioGroupContext);
|
|
96
|
+
const isRadio = type === "radio";
|
|
97
|
+
const isCheckBox = type === "checkbox";
|
|
98
|
+
const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
|
|
99
|
+
const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
|
|
58
100
|
|
|
59
|
-
|
|
60
|
-
|
|
101
|
+
// FIXME handle click seems to be a combination of multiple event types
|
|
102
|
+
const handleClick = (e: any) => {
|
|
103
|
+
if (isDisabled) {
|
|
104
|
+
e.stopPropagation();
|
|
105
|
+
e.preventDefault();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
61
108
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (isAnchor) {
|
|
66
|
-
itemRef.current.click();
|
|
67
|
-
} else {
|
|
68
|
-
handleClick(e);
|
|
69
|
-
}
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
109
|
+
const event: RMEvent = {
|
|
110
|
+
value,
|
|
111
|
+
syntheticEvent: e,
|
|
72
112
|
};
|
|
113
|
+
if (e.key !== undefined) event.key = e.key;
|
|
114
|
+
if (isCheckBox) event.checked = !isChecked;
|
|
115
|
+
if (isRadio) event.name = radioGroup.name;
|
|
116
|
+
safeCall(onClick, event);
|
|
117
|
+
if (isRadio) safeCall(radioGroup.onRadioChange, event);
|
|
118
|
+
eventHandlers.handleClick(event, isCheckBox || isRadio);
|
|
119
|
+
};
|
|
73
120
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
type,
|
|
77
|
-
disabled: isDisabled,
|
|
78
|
-
hover: isHovering,
|
|
79
|
-
checked: isChecked,
|
|
80
|
-
anchor: isAnchor,
|
|
81
|
-
}),
|
|
82
|
-
[type, isDisabled, isHovering, isChecked, isAnchor],
|
|
83
|
-
);
|
|
121
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
122
|
+
if (!isHovering) return;
|
|
84
123
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
124
|
+
switch (e.key) {
|
|
125
|
+
case Keys.ENTER:
|
|
126
|
+
case Keys.SPACE:
|
|
127
|
+
if (isAnchor) {
|
|
128
|
+
menuItemRef?.current && menuItemRef.current.click();
|
|
129
|
+
} else {
|
|
130
|
+
handleClick(e);
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
94
135
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
|
|
106
|
-
children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
|
|
107
|
-
};
|
|
136
|
+
const modifiers = useMemo(
|
|
137
|
+
() => ({
|
|
138
|
+
type,
|
|
139
|
+
disabled: isDisabled,
|
|
140
|
+
hover: isHovering,
|
|
141
|
+
checked: isChecked,
|
|
142
|
+
anchor: isAnchor,
|
|
143
|
+
}),
|
|
144
|
+
[type, isDisabled, isHovering, isChecked, isAnchor],
|
|
145
|
+
);
|
|
108
146
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
)
|
|
147
|
+
const mergedProps = mergeProps(
|
|
148
|
+
{
|
|
149
|
+
...restStateProps,
|
|
150
|
+
onPointerDown: setHover,
|
|
151
|
+
onKeyDown: handleKeyDown,
|
|
152
|
+
onClick: handleClick,
|
|
153
|
+
},
|
|
154
|
+
restProps,
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
// Order of props overriding (same in all components):
|
|
158
|
+
// 1. Preset props adhering to WAI-ARIA Authoring Practices.
|
|
159
|
+
// 2. Merged outer and local props
|
|
160
|
+
// 3. ref, className
|
|
161
|
+
const menuItemProps = {
|
|
162
|
+
role: isRadio ? "menuitemradio" : isCheckBox ? "menuitemcheckbox" : "menuitem",
|
|
163
|
+
"aria-checked": isRadio || isCheckBox ? isChecked : undefined,
|
|
164
|
+
...mergedProps,
|
|
165
|
+
...commonProps(isDisabled, isHovering),
|
|
166
|
+
ref: useCombinedRef(externalRef as Ref<any>, menuItemRef),
|
|
167
|
+
className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
|
|
168
|
+
children: useMemo(() => safeCall(children, modifiers), [children, modifiers]),
|
|
169
|
+
};
|
|
120
170
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
171
|
+
if (isAnchor) {
|
|
172
|
+
return (
|
|
173
|
+
<li role="presentation">
|
|
174
|
+
<a href={href} {...menuItemProps} />
|
|
175
|
+
</li>
|
|
176
|
+
);
|
|
177
|
+
} else {
|
|
178
|
+
return <li {...menuItemProps} />;
|
|
179
|
+
}
|
|
130
180
|
};
|
|
181
|
+
|
|
182
|
+
export const MenuItem = withHovering("MenuItem", MenuItemFr);
|