@linzjs/step-ag-grid 1.4.6 → 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 +108 -88
- 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 +2 -2
- package/dist/src/react-menu3/components/Menu.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuButton.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuDivider.d.ts +3 -3
- package/dist/src/react-menu3/components/MenuGroup.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuHeader.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuItem.d.ts +2 -4
- package/dist/src/react-menu3/components/MenuList.d.ts +2 -56
- package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +2 -2
- package/dist/src/react-menu3/components/SubMenu.d.ts +6 -6
- package/dist/src/react-menu3/hooks/useBEM.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useItems.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useMenuChange.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useMenuState.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useMenuStateAndFocus.d.ts +1 -1
- package/dist/src/react-menu3/index.d.ts +1 -391
- package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +1 -1
- package/dist/src/react-menu3/types.d.ts +389 -0
- package/dist/src/react-menu3/utils/constants.d.ts +12 -5
- package/dist/src/react-menu3/utils/index.d.ts +0 -1
- package/dist/src/react-menu3/utils/{propTypes.d.ts → propTypes2.d.ts} +0 -0
- package/dist/src/react-menu3/utils/utils.d.ts +2 -2
- package/dist/step-ag-grid.esm.js +99 -90
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/GridCell.tsx +6 -3
- package/src/components/GridPopoverHook.tsx +1 -1
- package/src/components/gridForm/GridFormMultiSelect.tsx +32 -19
- 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 -46
- package/src/react-menu3/components/FocusableItem.tsx +2 -2
- package/src/react-menu3/components/Menu.tsx +1 -1
- package/src/react-menu3/components/MenuButton.tsx +1 -1
- package/src/react-menu3/components/MenuDivider.tsx +2 -2
- package/src/react-menu3/components/MenuGroup.tsx +1 -1
- package/src/react-menu3/components/MenuHeader.tsx +1 -1
- package/src/react-menu3/components/MenuItem.tsx +2 -3
- package/src/react-menu3/components/MenuList.tsx +19 -62
- package/src/react-menu3/components/MenuRadioGroup.tsx +2 -2
- package/src/react-menu3/components/SubMenu.tsx +17 -8
- package/src/react-menu3/hooks/useBEM.ts +1 -1
- package/src/react-menu3/hooks/useItems.ts +1 -1
- package/src/react-menu3/hooks/useMenuChange.ts +1 -1
- package/src/react-menu3/hooks/useMenuState.ts +1 -1
- package/src/react-menu3/hooks/useMenuStateAndFocus.ts +1 -1
- package/src/react-menu3/index.ts +1 -431
- package/src/react-menu3/positionUtils/getPositionHelpers.ts +3 -3
- package/src/react-menu3/positionUtils/placeLeftorRight.ts +1 -1
- package/src/react-menu3/positionUtils/placeToporBottom.ts +1 -1
- package/src/react-menu3/positionUtils/positionContextMenu.ts +1 -1
- package/src/react-menu3/positionUtils/positionMenu.ts +1 -1
- package/src/react-menu3/{index.d.ts → types.ts} +106 -359
- package/src/react-menu3/utils/constants.ts +24 -5
- package/src/react-menu3/utils/index.ts +1 -1
- package/src/react-menu3/utils/{propTypes.ts → propTypes2.ts} +0 -0
- package/src/react-menu3/utils/utils.ts +2 -2
- package/src/stories/components/GridReadOnly.stories.tsx +3 -4
package/package.json
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback, useContext, useMemo, useState } from "react";
|
|
1
|
+
import { ForwardedRef, forwardRef, useCallback, useContext, useMemo, useState } from "react";
|
|
2
2
|
import { GridBaseRow } from "./Grid";
|
|
3
3
|
import { UpdatingContext } from "@contexts/UpdatingContext";
|
|
4
4
|
import { GridContext } from "@contexts/GridContext";
|
|
@@ -27,7 +27,7 @@ export interface GenericCellEditorColDef<
|
|
|
27
27
|
FormProps extends GenericCellEditorParams<RowType>,
|
|
28
28
|
> extends ColDef {
|
|
29
29
|
cellEditorParams?: FormProps;
|
|
30
|
-
cellRendererParams?: GenericCellRendererParams
|
|
30
|
+
cellRendererParams?: GenericCellRendererParams<RowType>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export const GridCellRenderer = (cellRendererParams: ICellRendererParams) => {
|
|
@@ -77,8 +77,9 @@ interface GenericCellEditorICellEditorParams<RowType extends GridBaseRow, FormPr
|
|
|
77
77
|
colDef: GenericCellEditorColDef<RowType, FormProps>;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
export const
|
|
80
|
+
export const GenericCellEditorComponentFr = <RowType extends GridBaseRow, FormProps extends Record<string, any>>(
|
|
81
81
|
props: GenericCellEditorICellEditorParams<RowType, FormProps>,
|
|
82
|
+
_: ForwardedRef<any>, // We don't forward the ref, as that's for generic aggrid cell editing
|
|
82
83
|
) => {
|
|
83
84
|
const { updatingCells, getSelectedRows } = useContext(GridContext);
|
|
84
85
|
|
|
@@ -123,3 +124,5 @@ export const GenericCellEditorComponent = <RowType extends GridBaseRow, FormProp
|
|
|
123
124
|
</>
|
|
124
125
|
);
|
|
125
126
|
};
|
|
127
|
+
|
|
128
|
+
export const GenericCellEditorComponent = forwardRef(GenericCellEditorComponentFr);
|
|
@@ -3,7 +3,7 @@ import { useCallback, useContext, useEffect, useRef, useState } from "react";
|
|
|
3
3
|
import { GridContext } from "@contexts/GridContext";
|
|
4
4
|
import { GridFormProps } from "./GridCell";
|
|
5
5
|
import { GridBaseRow } from "./Grid";
|
|
6
|
-
import { ControlledMenu } from "
|
|
6
|
+
import { ControlledMenu } from "@react-menu3";
|
|
7
7
|
|
|
8
8
|
export const useGridPopoverHook = <RowType extends GridBaseRow>(
|
|
9
9
|
props: GridFormProps<RowType>,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "../../react-menu3/styles/index.scss";
|
|
2
2
|
|
|
3
|
-
import { MenuItem, MenuDivider, FocusableItem,
|
|
4
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { MenuItem, MenuDivider, FocusableItem, ClickEvent } from "@react-menu3";
|
|
4
|
+
import { Fragment, useCallback, useEffect, useRef, useState, KeyboardEvent } from "react";
|
|
5
5
|
import { GridBaseRow } from "../Grid";
|
|
6
6
|
import { ComponentLoadingWrapper } from "../ComponentLoadingWrapper";
|
|
7
7
|
import { delay } from "lodash-es";
|
|
@@ -99,7 +99,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
|
|
|
99
99
|
return undefined;
|
|
100
100
|
}
|
|
101
101
|
const str = (option.label as string) || "";
|
|
102
|
-
return str.toLowerCase().indexOf(filter) === -1 ? option.value : undefined;
|
|
102
|
+
return str.toLowerCase().indexOf(filter.trim()) === -1 ? option.value : undefined;
|
|
103
103
|
})
|
|
104
104
|
.filter((r) => r !== undefined),
|
|
105
105
|
);
|
|
@@ -110,7 +110,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
|
|
|
110
110
|
<div className={"Grid-popoverContainerList"}>
|
|
111
111
|
{options && formProps.filtered && (
|
|
112
112
|
<>
|
|
113
|
-
<FocusableItem className={"filter-item"}>
|
|
113
|
+
<FocusableItem className={"filter-item"} key={"filter"}>
|
|
114
114
|
{({ ref }: any) => (
|
|
115
115
|
<div style={{ display: "flex", width: "100%" }}>
|
|
116
116
|
<input
|
|
@@ -134,34 +134,47 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
|
|
|
134
134
|
item.value === MenuSeparatorString ? (
|
|
135
135
|
<MenuDivider key={`$$divider_${index}`} />
|
|
136
136
|
) : filteredValues.includes(item.value) ? null : (
|
|
137
|
-
|
|
137
|
+
<Fragment key={`${index}`}>
|
|
138
138
|
<MenuItem
|
|
139
|
-
key={`${
|
|
140
|
-
onClick={(e:
|
|
141
|
-
// FIXME Matt Event type guessed here
|
|
139
|
+
key={`${index}`}
|
|
140
|
+
onClick={(e: ClickEvent) => {
|
|
142
141
|
e.keepOpen = true;
|
|
143
|
-
if (selectedValues.includes(
|
|
142
|
+
if (selectedValues.includes(item.value)) {
|
|
144
143
|
setSelectedValues(selectedValues.filter((value) => value != item.value));
|
|
145
144
|
} else {
|
|
146
|
-
setSelectedValues([...selectedValues, item.value
|
|
145
|
+
setSelectedValues([...selectedValues, item.value]);
|
|
146
|
+
}
|
|
147
|
+
}}
|
|
148
|
+
onKeyDown={async (e: KeyboardEvent) => {
|
|
149
|
+
if (e.key === "Enter") triggerSave().then();
|
|
150
|
+
else if (e.key === " ") {
|
|
151
|
+
if (selectedValues.includes(item.value)) {
|
|
152
|
+
setSelectedValues(selectedValues.filter((value) => value != item.value));
|
|
153
|
+
} else {
|
|
154
|
+
setSelectedValues([...selectedValues, item.value]);
|
|
155
|
+
}
|
|
156
|
+
e.preventDefault();
|
|
157
|
+
e.stopPropagation();
|
|
147
158
|
}
|
|
148
|
-
return false;
|
|
149
159
|
}}
|
|
150
|
-
onKeyDown={async (e) => e.key === "Enter" && triggerSave().then()}
|
|
151
160
|
>
|
|
152
161
|
<LuiCheckboxInput
|
|
153
162
|
isChecked={selectedValues.includes(item.value)}
|
|
154
163
|
value={`${item.value}`}
|
|
155
164
|
label={item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
165
|
+
inputProps={{
|
|
166
|
+
onClick: (e) => {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
e.stopPropagation();
|
|
169
|
+
return false;
|
|
170
|
+
},
|
|
171
|
+
}}
|
|
172
|
+
onChange={() => {
|
|
173
|
+
/*Do nothing, change handled by menuItem*/
|
|
162
174
|
}}
|
|
163
175
|
/>
|
|
164
176
|
</MenuItem>
|
|
177
|
+
|
|
165
178
|
{selectedValues.includes(item.value) && item.subComponent && (
|
|
166
179
|
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`}>
|
|
167
180
|
{(ref: any) =>
|
|
@@ -177,7 +190,7 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(prop
|
|
|
177
190
|
}
|
|
178
191
|
</FocusableItem>
|
|
179
192
|
)}
|
|
180
|
-
|
|
193
|
+
</Fragment>
|
|
181
194
|
),
|
|
182
195
|
)}
|
|
183
196
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./GridRenderGenericCell.scss";
|
|
2
2
|
|
|
3
3
|
import { useContext } from "react";
|
|
4
|
-
import { UpdatingContext } from "
|
|
4
|
+
import { UpdatingContext } from "@contexts/UpdatingContext";
|
|
5
5
|
import { GridLoadableCell } from "../GridLoadableCell";
|
|
6
6
|
import { GridIcon } from "../GridIcon";
|
|
7
7
|
import { ColDef, ICellRendererParams } from "ag-grid-community";
|
|
@@ -9,21 +9,25 @@ import { ValueFormatterParams } from "ag-grid-community/dist/lib/entities/colDef
|
|
|
9
9
|
import { GenericCellEditorParams } from "../GridCell";
|
|
10
10
|
import { GridBaseRow } from "../Grid";
|
|
11
11
|
|
|
12
|
+
export interface RowICellRendererParams<RowType extends GridBaseRow> extends ICellRendererParams {
|
|
13
|
+
data: RowType;
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
export interface GenericCellColDef<RowType extends GridBaseRow, FormProps extends Record<string, any>> extends ColDef {
|
|
13
|
-
cellRendererParams?: GenericCellRendererParams
|
|
17
|
+
cellRendererParams?: GenericCellRendererParams<RowType>;
|
|
14
18
|
cellEditorParams?: GenericCellEditorParams<RowType> & FormProps;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
export interface GenericCellRendererParams {
|
|
21
|
+
export interface GenericCellRendererParams<RowType extends GridBaseRow> {
|
|
18
22
|
singleClickEdit?: boolean;
|
|
19
|
-
warning?: (props:
|
|
20
|
-
info?: (props:
|
|
23
|
+
warning?: (props: RowICellRendererParams<RowType>) => string | boolean | undefined;
|
|
24
|
+
info?: (props: RowICellRendererParams<RowType>) => string | boolean | undefined;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
export const GridRendererGenericCell = (props: ICellRendererParams): JSX.Element => {
|
|
27
|
+
export const GridRendererGenericCell = <RowType extends GridBaseRow>(props: ICellRendererParams): JSX.Element => {
|
|
24
28
|
const { checkUpdating } = useContext(UpdatingContext);
|
|
25
29
|
|
|
26
|
-
const cellRendererParams = props.colDef?.cellRendererParams as GenericCellRendererParams | undefined;
|
|
30
|
+
const cellRendererParams = props.colDef?.cellRendererParams as GenericCellRendererParams<RowType> | undefined;
|
|
27
31
|
const warningFn = cellRendererParams?.warning;
|
|
28
32
|
const warningText = warningFn ? warningFn(props) : undefined;
|
|
29
33
|
const infoFn = cellRendererParams?.info;
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import { useContext } from "react";
|
|
2
|
-
import { ICellRendererParams } from "ag-grid-community";
|
|
2
|
+
import { ColDef, ICellRendererParams } from "ag-grid-community";
|
|
3
3
|
import { UpdatingContext } from "@contexts/UpdatingContext";
|
|
4
4
|
import { GridLoadableCell } from "../GridLoadableCell";
|
|
5
5
|
import { LuiIcon } from "@linzjs/lui";
|
|
6
|
+
import { Column } from "ag-grid-community/dist/lib/entities/column";
|
|
6
7
|
|
|
7
8
|
export const GridRenderPopoutMenuCell = (props: ICellRendererParams) => {
|
|
8
9
|
const { checkUpdating } = useContext(UpdatingContext);
|
|
9
10
|
const isLoading = checkUpdating(props.colDef?.field ?? "", props.data.id);
|
|
10
|
-
const
|
|
11
|
+
const editable = props.colDef?.editable;
|
|
12
|
+
const disabled = !(typeof editable === "function"
|
|
13
|
+
? editable({
|
|
14
|
+
node: props.node,
|
|
15
|
+
data: props.data,
|
|
16
|
+
column: props.column as Column,
|
|
17
|
+
colDef: props.colDef as ColDef,
|
|
18
|
+
api: props.api,
|
|
19
|
+
columnApi: props.columnApi,
|
|
20
|
+
context: props.context,
|
|
21
|
+
})
|
|
22
|
+
: editable);
|
|
11
23
|
|
|
12
24
|
return (
|
|
13
25
|
<GridLoadableCell
|
|
@@ -258,9 +258,10 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
258
258
|
}
|
|
259
259
|
// This is needed to trigger postSortRowsHook
|
|
260
260
|
gridApi.refreshClientSideRowModel();
|
|
261
|
-
|
|
261
|
+
} else {
|
|
262
|
+
// Don't set saving if ok as the form has already closed
|
|
263
|
+
setSaving && setSaving(false);
|
|
262
264
|
}
|
|
263
|
-
setSaving && setSaving(false);
|
|
264
265
|
return ok;
|
|
265
266
|
});
|
|
266
267
|
};
|
|
@@ -1,28 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useRef,
|
|
4
|
+
useMemo,
|
|
5
|
+
useCallback,
|
|
6
|
+
useEffect,
|
|
7
|
+
KeyboardEvent,
|
|
8
|
+
FocusEvent,
|
|
9
|
+
MutableRefObject,
|
|
10
|
+
ForwardedRef,
|
|
11
|
+
} from "react";
|
|
4
12
|
import { createPortal } from "react-dom";
|
|
5
|
-
import { string, number, bool, func, object, oneOf, oneOfType, exact } from "prop-types";
|
|
6
13
|
import { MenuList } from "./MenuList";
|
|
7
14
|
import { useBEM } from "../hooks";
|
|
8
15
|
import {
|
|
9
|
-
rootMenuPropTypes,
|
|
10
16
|
menuContainerClass,
|
|
11
17
|
mergeProps,
|
|
12
18
|
safeCall,
|
|
13
19
|
isMenuOpen,
|
|
14
20
|
getTransition,
|
|
15
|
-
values,
|
|
16
21
|
CloseReason,
|
|
17
22
|
Keys,
|
|
18
|
-
MenuStateMap,
|
|
19
23
|
EventHandlersContext,
|
|
20
24
|
SettingsContext,
|
|
21
25
|
ItemSettingsContext,
|
|
22
26
|
} from "../utils";
|
|
23
27
|
import { hasParentClass } from "@utils/util";
|
|
28
|
+
import { ControlledMenuProps, PortalFieldType, RadioChangeEvent } from "../types";
|
|
24
29
|
|
|
25
|
-
export const
|
|
30
|
+
export const ControlledMenuFr = (
|
|
26
31
|
{
|
|
27
32
|
"aria-label": ariaLabel,
|
|
28
33
|
className,
|
|
@@ -44,11 +49,11 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
44
49
|
onClose,
|
|
45
50
|
saveButtonRef,
|
|
46
51
|
...restProps
|
|
47
|
-
}:
|
|
48
|
-
externalRef
|
|
49
|
-
) {
|
|
50
|
-
const containerRef = useRef(
|
|
51
|
-
const scrollNodesRef = useRef<{anchors?:HTMLDivElement[]}>({});
|
|
52
|
+
}: ControlledMenuProps & { saveButtonRef?: MutableRefObject<HTMLButtonElement | null> },
|
|
53
|
+
externalRef: ForwardedRef<HTMLUListElement>,
|
|
54
|
+
) => {
|
|
55
|
+
const containerRef = useRef<HTMLElement>();
|
|
56
|
+
const scrollNodesRef = useRef<{ anchors?: HTMLDivElement[] }>({});
|
|
52
57
|
const { anchorRef, state } = restProps;
|
|
53
58
|
|
|
54
59
|
const settings = useMemo(
|
|
@@ -92,7 +97,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
92
97
|
// the cell doesn't refresh during update if save is invoked from a native event
|
|
93
98
|
// This doesn't happen in React18
|
|
94
99
|
// To work around it, I invoke the save by clicking on a passed in invisible button ref
|
|
95
|
-
if (saveButtonRef
|
|
100
|
+
if (saveButtonRef?.current) saveButtonRef.current.click();
|
|
96
101
|
else safeCall(onClose, { reason: CloseReason.BLUR });
|
|
97
102
|
|
|
98
103
|
// If a user clicks on the menu button when a menu is open, we need to close the menu.
|
|
@@ -107,7 +112,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
107
112
|
}
|
|
108
113
|
}
|
|
109
114
|
},
|
|
110
|
-
[clickIsWithinMenu, onClose],
|
|
115
|
+
[clickIsWithinMenu, onClose, saveButtonRef, skipOpen],
|
|
111
116
|
);
|
|
112
117
|
|
|
113
118
|
const handleScreenEventForCancel = useCallback(
|
|
@@ -122,7 +127,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
122
127
|
|
|
123
128
|
useEffect(() => {
|
|
124
129
|
if (isMenuOpen(state)) {
|
|
125
|
-
const thisDocument = anchorRef
|
|
130
|
+
const thisDocument = anchorRef?.current ? anchorRef?.current.ownerDocument : document;
|
|
126
131
|
thisDocument.addEventListener("mousedown", handleScreenEventForCancel, true);
|
|
127
132
|
thisDocument.addEventListener("mouseup", handleScreenEventForSave, true);
|
|
128
133
|
thisDocument.addEventListener("click", handleScreenEventForCancel, true);
|
|
@@ -135,7 +140,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
135
140
|
};
|
|
136
141
|
}
|
|
137
142
|
return () => {};
|
|
138
|
-
}, [handleScreenEventForSave, handleScreenEventForCancel, state]);
|
|
143
|
+
}, [handleScreenEventForSave, handleScreenEventForCancel, state, anchorRef]);
|
|
139
144
|
|
|
140
145
|
const itemSettings = useMemo(
|
|
141
146
|
() => ({
|
|
@@ -147,7 +152,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
147
152
|
|
|
148
153
|
const eventHandlers = useMemo(
|
|
149
154
|
() => ({
|
|
150
|
-
handleClick(event,
|
|
155
|
+
handleClick(event: RadioChangeEvent, isCheckOrRadio: boolean) {
|
|
151
156
|
if (!event.stopPropagation) safeCall(onItemClick, event);
|
|
152
157
|
|
|
153
158
|
let keepOpen = event.keepOpen;
|
|
@@ -155,7 +160,7 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
155
160
|
// if event.keepOpen is undefined, the following default behaviour is used
|
|
156
161
|
// According to WAI-ARIA Authoring Practices 1.1
|
|
157
162
|
// Keep menu open when check or radio is invoked by SPACE key
|
|
158
|
-
keepOpen =
|
|
163
|
+
keepOpen = isCheckOrRadio && event.key === Keys.SPACE;
|
|
159
164
|
}
|
|
160
165
|
|
|
161
166
|
if (!keepOpen) {
|
|
@@ -167,14 +172,14 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
167
172
|
}
|
|
168
173
|
},
|
|
169
174
|
|
|
170
|
-
handleClose(key) {
|
|
175
|
+
handleClose(key?: string) {
|
|
171
176
|
safeCall(onClose, { key, reason: CloseReason.CLICK });
|
|
172
177
|
},
|
|
173
178
|
}),
|
|
174
179
|
[onItemClick, onClose],
|
|
175
180
|
);
|
|
176
181
|
|
|
177
|
-
const onKeyDown = ({ key }) => {
|
|
182
|
+
const onKeyDown = ({ key }: KeyboardEvent) => {
|
|
178
183
|
switch (key) {
|
|
179
184
|
case Keys.ESC:
|
|
180
185
|
safeCall(onClose, { key, reason: CloseReason.CANCEL });
|
|
@@ -182,14 +187,14 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
182
187
|
}
|
|
183
188
|
};
|
|
184
189
|
|
|
185
|
-
const onBlur = (e) => {
|
|
190
|
+
const onBlur = (e: FocusEvent) => {
|
|
186
191
|
if (isMenuOpen(state) && !e.currentTarget.contains(e.relatedTarget || document.activeElement)) {
|
|
187
192
|
safeCall(onClose, { reason: CloseReason.BLUR });
|
|
188
193
|
|
|
189
194
|
// If a user clicks on the menu button when a menu is open, we need to close the menu.
|
|
190
195
|
// However, a blur event will be fired prior to the click event on menu button,
|
|
191
196
|
// which makes the menu first close and then open again.
|
|
192
|
-
// If this
|
|
197
|
+
// If this happens, e.relatedTarget is incorrectly set to null instead of the button in Safari and Firefox,
|
|
193
198
|
// and makes it difficult to determine whether onBlur is fired because of clicking on menu button.
|
|
194
199
|
// This is a workaround approach which sets a flag to skip a following click event.
|
|
195
200
|
if (skipOpen) {
|
|
@@ -231,31 +236,20 @@ export const ControlledMenu = forwardRef(function ControlledMenu(
|
|
|
231
236
|
</div>
|
|
232
237
|
);
|
|
233
238
|
|
|
234
|
-
if (portal === true && anchorRef
|
|
235
|
-
portal = { target: anchorRef.current.ownerDocument.body };
|
|
239
|
+
if (portal === true && anchorRef?.current !== undefined) {
|
|
240
|
+
portal = { target: anchorRef.current.ownerDocument.body } as PortalFieldType;
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
if (portal
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
243
|
+
if (portal) {
|
|
244
|
+
if (typeof portal === "boolean") {
|
|
245
|
+
if (portal && typeof document !== "undefined") {
|
|
246
|
+
return createPortal(menuList, document.body);
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
return portal.target ? createPortal(menuList, portal.target) : portal.stablePosition ? null : menuList;
|
|
250
|
+
}
|
|
242
251
|
}
|
|
243
252
|
return menuList;
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
ControlledMenu.propTypes /* remove-proptypes */ = {
|
|
247
|
-
...rootMenuPropTypes,
|
|
248
|
-
state: oneOf(values(MenuStateMap)),
|
|
249
|
-
anchorPoint: exact({
|
|
250
|
-
x: number,
|
|
251
|
-
y: number,
|
|
252
|
-
}),
|
|
253
|
-
anchorRef: object,
|
|
254
|
-
skipOpen: object,
|
|
255
|
-
captureFocus: bool,
|
|
256
|
-
menuItemFocus: exact({
|
|
257
|
-
position: oneOfType([string, number]),
|
|
258
|
-
alwaysUpdate: bool,
|
|
259
|
-
}),
|
|
260
|
-
onClose: func,
|
|
261
253
|
};
|
|
254
|
+
|
|
255
|
+
export const ControlledMenu = forwardRef(ControlledMenuFr);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
withHovering,
|
|
10
10
|
EventHandlersContext,
|
|
11
11
|
} from "../utils";
|
|
12
|
-
import { BaseProps } from "../
|
|
12
|
+
import { BaseProps } from "../types";
|
|
13
13
|
import { withHoveringResultProps } from "../utils/withHovering";
|
|
14
14
|
|
|
15
15
|
export interface FocusableItemProps extends BaseProps, withHoveringResultProps {
|
|
@@ -72,4 +72,4 @@ export const FocusableItemFr = ({
|
|
|
72
72
|
);
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
export const FocusableItem = withHovering("FocusableItem", FocusableItemFr)
|
|
75
|
+
export const FocusableItem = withHovering("FocusableItem", FocusableItemFr);
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import { ControlledMenu } from "./ControlledMenu";
|
|
12
12
|
import { useMenuChange, useMenuStateAndFocus, useCombinedRef } from "../hooks";
|
|
13
13
|
import { getName, mergeProps, safeCall, isMenuOpen, Keys, FocusPositions } from "../utils";
|
|
14
|
-
import { MenuButtonModifiers, RenderProp, RootMenuProps, UncontrolledMenuProps } from "../
|
|
14
|
+
import { MenuButtonModifiers, RenderProp, RootMenuProps, UncontrolledMenuProps } from "../types";
|
|
15
15
|
|
|
16
16
|
//
|
|
17
17
|
// Menu
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { forwardRef, LegacyRef, ReactNode, useMemo } from "react";
|
|
2
2
|
import { useBEM } from "../hooks";
|
|
3
3
|
import { menuButtonClass } from "../utils";
|
|
4
|
-
import { BaseProps, MenuButtonModifiers } from "../
|
|
4
|
+
import { BaseProps, MenuButtonModifiers } from "../types";
|
|
5
5
|
|
|
6
6
|
export interface MenuButtonProps extends BaseProps<MenuButtonModifiers> {
|
|
7
7
|
disabled?: boolean;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memo, forwardRef, LegacyRef } from "react";
|
|
2
2
|
import { useBEM } from "../hooks";
|
|
3
3
|
import { menuClass, menuDividerClass } from "../utils";
|
|
4
|
-
import { BaseProps } from "../
|
|
4
|
+
import { BaseProps } from "../types";
|
|
5
5
|
|
|
6
6
|
const MenuDividerFr = ({ className, ...restProps }: BaseProps, externalRef: LegacyRef<HTMLLIElement>) => {
|
|
7
7
|
return (
|
|
@@ -14,4 +14,4 @@ const MenuDividerFr = ({ className, ...restProps }: BaseProps, externalRef: Lega
|
|
|
14
14
|
);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
export const MenuDivider = memo(forwardRef(MenuDividerFr))
|
|
17
|
+
export const MenuDivider = memo(forwardRef(MenuDividerFr));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ForwardedRef, forwardRef, ReactNode, useContext, useRef, useState } from "react";
|
|
2
2
|
import { useBEM, useLayoutEffect, useCombinedRef } from "../hooks";
|
|
3
3
|
import { menuClass, menuGroupClass, MenuListContext } from "../utils";
|
|
4
|
-
import { BaseProps, MenuOverflow } from "../
|
|
4
|
+
import { BaseProps, MenuOverflow } from "../types";
|
|
5
5
|
|
|
6
6
|
export interface MenuGroupProps extends BaseProps {
|
|
7
7
|
children?: ReactNode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { memo, forwardRef, ForwardedRef } from "react";
|
|
2
2
|
import { useBEM } from "../hooks";
|
|
3
3
|
import { menuClass, menuHeaderClass } from "../utils";
|
|
4
|
-
import { BaseProps } from "../
|
|
4
|
+
import { BaseProps } from "../types";
|
|
5
5
|
|
|
6
6
|
export const MenuHeaderFr = ({ className, ...restProps }: BaseProps, externalRef: ForwardedRef<HTMLLIElement>) => {
|
|
7
7
|
return (
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
Keys,
|
|
13
13
|
RMEvent,
|
|
14
14
|
} from "../utils";
|
|
15
|
-
import { BaseProps, ClickEvent, EventHandler, Hoverable, MenuItemTypeProp, RenderProp } from "../
|
|
15
|
+
import { BaseProps, ClickEvent, EventHandler, Hoverable, MenuItemTypeProp, RenderProp } from "../types";
|
|
16
16
|
import { withHoveringResultProps } from "../utils/withHovering";
|
|
17
17
|
|
|
18
18
|
//
|
|
@@ -179,5 +179,4 @@ const MenuItemFr = ({
|
|
|
179
179
|
}
|
|
180
180
|
};
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
export const MenuItem = withHovering("MenuItem", MenuItemFr) as any as typeof MenuItemFr;
|
|
182
|
+
export const MenuItem = withHovering("MenuItem", MenuItemFr);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useReducer, useEffect, useRef, useMemo, useCallback, useContext
|
|
1
|
+
import { useState, useReducer, useEffect, useRef, useMemo, useCallback, useContext } from "react";
|
|
2
2
|
import { flushSync } from "react-dom";
|
|
3
3
|
import { useBEM, useCombinedRef, useLayoutEffect, useItems } from "../hooks";
|
|
4
4
|
import { getPositionHelpers, positionMenu, positionContextMenu } from "../positionUtils";
|
|
@@ -22,65 +22,7 @@ import {
|
|
|
22
22
|
MenuListItemContext,
|
|
23
23
|
HoverItemContext,
|
|
24
24
|
} from "../utils";
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
interface ExtraMenuProps {
|
|
28
|
-
isDisabled?: boolean;
|
|
29
|
-
ariaLabel?: string;
|
|
30
|
-
containerRef: MutableRefObject<HTMLElement>;
|
|
31
|
-
externalRef: MutableRefObject<HTMLUListElement>;
|
|
32
|
-
parentScrollingRef: MutableRefObject<any>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
// ControlledMenu
|
|
37
|
-
// ----------------------------------------------------------------------
|
|
38
|
-
export interface ControlledMenuProps extends RootMenuProps, ExtraMenuProps {
|
|
39
|
-
/**
|
|
40
|
-
* Viewport coordinates to which context menu will be positioned.
|
|
41
|
-
*
|
|
42
|
-
* *Use this prop only for context menu*
|
|
43
|
-
*/
|
|
44
|
-
anchorPoint?: {
|
|
45
|
-
x: number;
|
|
46
|
-
y: number;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* A ref object attached to a DOM element to which menu will be positioned.
|
|
50
|
-
*
|
|
51
|
-
* *Don't set this prop for context menu*
|
|
52
|
-
*/
|
|
53
|
-
anchorRef?: React.MutableRefObject<HTMLElement>;
|
|
54
|
-
skipOpen?: React.RefObject<boolean>;
|
|
55
|
-
/**
|
|
56
|
-
* If `true`, the menu list element will gain focus after menu is open.
|
|
57
|
-
* @default true
|
|
58
|
-
*/
|
|
59
|
-
captureFocus?: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Controls the state of menu. When the prop is `undefined`, menu will be unmounted from DOM.
|
|
62
|
-
*/
|
|
63
|
-
state?: MenuState;
|
|
64
|
-
/**
|
|
65
|
-
* Sets which menu item receives focus (hover) when menu opens.
|
|
66
|
-
* You will usually set this prop when the menu is opened by keyboard events.
|
|
67
|
-
*
|
|
68
|
-
* *Note: If you don't intend to update focus (hover) position,
|
|
69
|
-
* it's important to keep this prop's identity stable when your component re-renders.*
|
|
70
|
-
*/
|
|
71
|
-
menuItemFocus?: {
|
|
72
|
-
position?: FocusPosition;
|
|
73
|
-
alwaysUpdate?: boolean;
|
|
74
|
-
};
|
|
75
|
-
/**
|
|
76
|
-
* Set the return value of `useMenuState` to this prop.
|
|
77
|
-
*/
|
|
78
|
-
endTransition?: () => void;
|
|
79
|
-
/**
|
|
80
|
-
* Event fired when menu is about to close.
|
|
81
|
-
*/
|
|
82
|
-
onClose?: EventHandler<MenuCloseEvent>;
|
|
83
|
-
}
|
|
25
|
+
import { ControlledMenuProps, MenuDirection } from "../types";
|
|
84
26
|
|
|
85
27
|
export const MenuList = ({
|
|
86
28
|
ariaLabel,
|
|
@@ -194,7 +136,7 @@ export const MenuList = ({
|
|
|
194
136
|
|
|
195
137
|
const handlePosition = useCallback(
|
|
196
138
|
(noOverflowCheck?: boolean) => {
|
|
197
|
-
if (!containerRef
|
|
139
|
+
if (!containerRef?.current) {
|
|
198
140
|
if (process.env.NODE_ENV !== "production") {
|
|
199
141
|
console.error(
|
|
200
142
|
'[React-Menu] Menu cannot be positioned properly as container ref is null. If you need to initialise `state` prop to "open" for ControlledMenu, please see this solution: https://codesandbox.io/s/initial-open-sp10wn',
|
|
@@ -403,7 +345,22 @@ export const MenuList = ({
|
|
|
403
345
|
() => {
|
|
404
346
|
// If focus has already been set to a children element, don't set focus on menu or item
|
|
405
347
|
if (!menuRef.current.contains(document.activeElement)) {
|
|
406
|
-
|
|
348
|
+
// Handle popover portal focus
|
|
349
|
+
const popupElement = focusRef.current?.nextSibling;
|
|
350
|
+
if (popupElement instanceof Element) {
|
|
351
|
+
const input = popupElement.querySelectorAll("input,textarea")[0] as HTMLElement;
|
|
352
|
+
if (input) {
|
|
353
|
+
input.focus();
|
|
354
|
+
// Text areas should start at end
|
|
355
|
+
if (input instanceof HTMLTextAreaElement) {
|
|
356
|
+
input.selectionStart = input.value.length;
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
focusRef.current?.focus();
|
|
360
|
+
}
|
|
361
|
+
} else {
|
|
362
|
+
focusRef.current?.focus();
|
|
363
|
+
}
|
|
407
364
|
setItemFocus();
|
|
408
365
|
}
|
|
409
366
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ForwardedRef, forwardRef, ReactNode, useMemo } from "react";
|
|
2
2
|
import { useBEM } from "../hooks";
|
|
3
3
|
import { menuClass, radioGroupClass, RadioGroupContext } from "../utils";
|
|
4
|
-
import { BaseProps, Event, EventHandler } from "../
|
|
4
|
+
import { BaseProps, Event, EventHandler } from "../types";
|
|
5
5
|
|
|
6
6
|
export interface RadioChangeEvent extends Event {
|
|
7
7
|
/**
|
|
@@ -69,4 +69,4 @@ export const MenuRadioGroupFr = (
|
|
|
69
69
|
);
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
export const MenuRadioGroup = forwardRef(MenuRadioGroupFr)
|
|
72
|
+
export const MenuRadioGroup = forwardRef(MenuRadioGroupFr);
|