@linzjs/step-ag-grid 23.0.0 → 24.0.0
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/src/components/ComponentLoadingWrapper.d.ts +1 -1
- package/dist/src/components/Grid.d.ts +17 -17
- package/dist/src/components/GridCell.d.ts +9 -9
- package/dist/src/components/GridCellFiller.d.ts +2 -2
- package/dist/src/components/GridCellMultiEditor.d.ts +6 -6
- package/dist/src/components/GridCellMultiSelectClassRules.d.ts +1 -1
- package/dist/src/components/GridIcon.d.ts +2 -2
- package/dist/src/components/GridNoRowsOverlay.d.ts +1 -1
- package/dist/src/components/GridPopoverHook.d.ts +2 -2
- package/dist/src/components/GridWrapper.d.ts +1 -1
- package/dist/src/components/PostSortRowsHook.d.ts +1 -1
- package/dist/src/components/clickInputWhenContainingCellClicked.d.ts +1 -1
- package/dist/src/components/gridFilter/GridFilterButtons.d.ts +5 -5
- package/dist/src/components/gridFilter/GridFilterColumnsToggle.d.ts +1 -1
- package/dist/src/components/gridFilter/GridFilterDownloadCsvButton.d.ts +1 -1
- package/dist/src/components/gridFilter/GridFilterHeaderIconButton.d.ts +2 -2
- package/dist/src/components/gridFilter/GridFilters.d.ts +1 -1
- package/dist/src/components/gridFilter/index.d.ts +7 -7
- package/dist/src/components/gridFilter/useGridFilter.d.ts +2 -2
- package/dist/src/components/gridForm/GridFormDropDown.d.ts +8 -8
- package/dist/src/components/gridForm/GridFormEditBearing.d.ts +2 -2
- package/dist/src/components/gridForm/GridFormMessage.d.ts +3 -3
- package/dist/src/components/gridForm/GridFormMultiSelect.d.ts +4 -4
- package/dist/src/components/gridForm/GridFormMultiSelectGrid.d.ts +4 -4
- package/dist/src/components/gridForm/GridFormPopoverMenu.d.ts +5 -5
- package/dist/src/components/gridForm/GridFormSubComponentTextArea.d.ts +4 -4
- package/dist/src/components/gridForm/GridFormSubComponentTextInput.d.ts +4 -4
- package/dist/src/components/gridForm/GridFormTextArea.d.ts +4 -4
- package/dist/src/components/gridForm/GridFormTextInput.d.ts +3 -3
- package/dist/src/components/gridForm/index.d.ts +10 -10
- package/dist/src/components/gridHeader/GridHeaderSelect.d.ts +1 -1
- package/dist/src/components/gridHeader/index.d.ts +1 -1
- package/dist/src/components/gridHook/index.d.ts +1 -1
- package/dist/src/components/gridHook/useGridContextMenu.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridButton.d.ts +5 -5
- package/dist/src/components/gridPopoverEdit/GridEditBoolean.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoutEditMultiSelectGrid.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverEditBearing.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverEditDropDown.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverMenu.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverMessage.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverTextArea.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/GridPopoverTextInput.d.ts +4 -4
- package/dist/src/components/gridPopoverEdit/index.d.ts +11 -11
- package/dist/src/components/gridRender/GridRenderGenericCell.d.ts +5 -5
- package/dist/src/components/gridRender/GridRenderPopoutMenuCell.d.ts +1 -1
- package/dist/src/components/gridRender/index.d.ts +2 -2
- package/dist/src/components/gridUtil.d.ts +1 -1
- package/dist/src/components/index.d.ts +19 -19
- package/dist/src/contexts/GridContext.d.ts +4 -4
- package/dist/src/contexts/GridContextProvider.d.ts +3 -3
- package/dist/src/contexts/GridPopoverContext.d.ts +3 -3
- package/dist/src/contexts/GridPopoverContextProvider.d.ts +4 -4
- package/dist/src/contexts/GridUpdatingContextProvider.d.ts +1 -1
- package/dist/src/index.d.ts +17 -17
- package/dist/src/lui/ActionButton.d.ts +9 -9
- package/dist/src/lui/FormError.d.ts +2 -2
- package/dist/src/lui/TextAreaInput.d.ts +1 -1
- package/dist/src/lui/TextInputFormatted.d.ts +2 -2
- package/dist/src/lui/reactUtils.d.ts +1 -1
- package/dist/src/lui/stateDeferredHook.d.ts +1 -1
- package/dist/src/react-menu3/components/ControlledMenu.d.ts +2 -2
- package/dist/src/react-menu3/components/FocusableItem.d.ts +3 -3
- package/dist/src/react-menu3/components/Menu.d.ts +3 -3
- package/dist/src/react-menu3/components/MenuButton.d.ts +2 -2
- package/dist/src/react-menu3/components/MenuDivider.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuGroup.d.ts +2 -2
- package/dist/src/react-menu3/components/MenuHeader.d.ts +2 -2
- package/dist/src/react-menu3/components/MenuItem.d.ts +3 -3
- package/dist/src/react-menu3/components/MenuList.d.ts +1 -1
- package/dist/src/react-menu3/components/MenuRadioGroup.d.ts +2 -2
- package/dist/src/react-menu3/components/SubMenu.d.ts +5 -5
- package/dist/src/react-menu3/contexts/EventHandlersContext.d.ts +1 -1
- package/dist/src/react-menu3/contexts/MenuListContext.d.ts +2 -2
- package/dist/src/react-menu3/contexts/MenuListItemContext.d.ts +1 -1
- package/dist/src/react-menu3/contexts/RadioGroupContext.d.ts +1 -1
- package/dist/src/react-menu3/contexts/SettingsContext.d.ts +2 -2
- package/dist/src/react-menu3/hooks/index.d.ts +9 -9
- package/dist/src/react-menu3/hooks/useBEM.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useCombinedRef.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useIsomorphicLayoutEffect.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useItemEffect.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useItemState.d.ts +1 -1
- package/dist/src/react-menu3/hooks/useItems.d.ts +2 -2
- 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 +11 -11
- package/dist/src/react-menu3/positionUtils/getPositionHelpers.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/index.d.ts +3 -3
- package/dist/src/react-menu3/positionUtils/placeArrowHorizontal.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/placeArrowVertical.d.ts +1 -1
- package/dist/src/react-menu3/positionUtils/placeLeftorRight.d.ts +4 -4
- package/dist/src/react-menu3/positionUtils/placeToporBottom.d.ts +5 -5
- package/dist/src/react-menu3/positionUtils/positionContextMenu.d.ts +2 -2
- package/dist/src/react-menu3/positionUtils/positionMenu.d.ts +5 -5
- package/dist/src/react-menu3/style-utils/index.d.ts +1 -1
- package/dist/src/react-menu3/types.d.ts +15 -15
- package/dist/src/react-menu3/utils/constants.d.ts +1 -1
- package/dist/src/react-menu3/utils/index.d.ts +3 -3
- package/dist/src/react-menu3/utils/utils.d.ts +5 -5
- package/dist/src/react-menu3/utils/withHovering.d.ts +1 -1
- package/dist/src/utils/testQuick.d.ts +2 -2
- package/dist/src/utils/testUtil.d.ts +2 -2
- package/dist/src/utils/textValidator.d.ts +2 -2
- package/dist/step-ag-grid.cjs.js +966 -952
- package/dist/step-ag-grid.cjs.js.map +1 -1
- package/dist/step-ag-grid.esm.js +968 -954
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +26 -41
- package/src/components/ComponentLoadingWrapper.tsx +5 -6
- package/src/components/Grid.tsx +85 -83
- package/src/components/GridCell.test.tsx +15 -15
- package/src/components/GridCell.tsx +46 -44
- package/src/components/GridCellFiller.tsx +5 -4
- package/src/components/GridCellMultiEditor.tsx +7 -7
- package/src/components/GridCellMultiSelectClassRules.tsx +3 -3
- package/src/components/GridIcon.tsx +6 -7
- package/src/components/GridLoadableCell.tsx +2 -2
- package/src/components/GridNoRowsOverlay.tsx +8 -8
- package/src/components/GridPopoverHook.tsx +16 -16
- package/src/components/GridWrapper.tsx +2 -2
- package/src/components/PostSortRowsHook.ts +11 -11
- package/src/components/clickInputWhenContainingCellClicked.tsx +5 -5
- package/src/components/gridFilter/GridFilterButtons.tsx +8 -9
- package/src/components/gridFilter/GridFilterColumnsToggle.tsx +25 -26
- package/src/components/gridFilter/GridFilterDownloadCsvButton.tsx +12 -13
- package/src/components/gridFilter/GridFilterHeaderIconButton.tsx +9 -10
- package/src/components/gridFilter/GridFilterQuick.tsx +6 -6
- package/src/components/gridFilter/GridFilters.tsx +1 -1
- package/src/components/gridFilter/index.ts +7 -7
- package/src/components/gridFilter/useGridFilter.ts +3 -3
- package/src/components/gridForm/GridFormDropDown.tsx +56 -52
- package/src/components/gridForm/GridFormEditBearing.tsx +12 -12
- package/src/components/gridForm/GridFormMessage.tsx +10 -10
- package/src/components/gridForm/GridFormMultiSelect.tsx +53 -51
- package/src/components/gridForm/GridFormMultiSelectGrid.tsx +25 -26
- package/src/components/gridForm/GridFormPopoverMenu.tsx +32 -29
- package/src/components/gridForm/GridFormSubComponentTextArea.tsx +10 -10
- package/src/components/gridForm/GridFormSubComponentTextInput.tsx +8 -8
- package/src/components/gridForm/GridFormTextArea.tsx +11 -11
- package/src/components/gridForm/GridFormTextInput.tsx +11 -11
- package/src/components/gridForm/index.ts +10 -10
- package/src/components/gridHeader/GridHeaderSelect.tsx +9 -9
- package/src/components/gridHeader/index.ts +1 -1
- package/src/components/gridHook/index.ts +1 -1
- package/src/components/gridHook/useGridContextMenu.tsx +7 -7
- package/src/components/gridPopoverEdit/GridButton.tsx +13 -12
- package/src/components/gridPopoverEdit/GridEditBoolean.tsx +19 -18
- package/src/components/gridPopoverEdit/GridPopoutEditMultiSelect.ts +7 -6
- package/src/components/gridPopoverEdit/GridPopoutEditMultiSelectGrid.ts +7 -6
- package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +9 -9
- package/src/components/gridPopoverEdit/GridPopoverEditDropDown.ts +8 -7
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +6 -6
- package/src/components/gridPopoverEdit/GridPopoverMessage.ts +4 -4
- package/src/components/gridPopoverEdit/GridPopoverTextArea.ts +4 -4
- package/src/components/gridPopoverEdit/GridPopoverTextInput.ts +4 -4
- package/src/components/gridPopoverEdit/index.ts +11 -11
- package/src/components/gridRender/GridRenderGenericCell.tsx +5 -5
- package/src/components/gridRender/GridRenderPopoutMenuCell.tsx +8 -9
- package/src/components/gridRender/index.ts +2 -2
- package/src/components/gridUtil.ts +3 -3
- package/src/components/index.ts +19 -19
- package/src/contexts/GridContext.tsx +52 -46
- package/src/contexts/GridContextProvider.test.tsx +14 -14
- package/src/contexts/GridContextProvider.tsx +42 -41
- package/src/contexts/GridPopoverContext.tsx +10 -7
- package/src/contexts/GridPopoverContextProvider.tsx +12 -10
- package/src/contexts/GridSubComponentContext.ts +6 -5
- package/src/contexts/GridUpdatingContext.tsx +5 -4
- package/src/contexts/GridUpdatingContextProvider.tsx +3 -3
- package/src/index.ts +17 -21
- package/src/lui/ActionButton.tsx +42 -41
- package/src/lui/FormError.tsx +4 -4
- package/src/lui/TextAreaInput.tsx +9 -9
- package/src/lui/TextInputFormatted.tsx +11 -11
- package/src/lui/reactUtils.test.tsx +8 -8
- package/src/lui/reactUtils.tsx +2 -2
- package/src/lui/stateDeferredHook.tsx +3 -5
- package/src/lui/timeoutHook.test.tsx +5 -5
- package/src/lui/timeoutHook.tsx +1 -1
- package/src/react-app-env.d.ts +1 -1
- package/src/react-menu3/components/ControlledMenu.tsx +48 -48
- package/src/react-menu3/components/FocusableItem.tsx +7 -7
- package/src/react-menu3/components/Menu.tsx +11 -11
- package/src/react-menu3/components/MenuButton.tsx +4 -4
- package/src/react-menu3/components/MenuDivider.tsx +4 -4
- package/src/react-menu3/components/MenuGroup.tsx +5 -5
- package/src/react-menu3/components/MenuHeader.tsx +4 -4
- package/src/react-menu3/components/MenuItem.tsx +14 -14
- package/src/react-menu3/components/MenuList.tsx +55 -55
- package/src/react-menu3/components/MenuRadioGroup.tsx +7 -7
- package/src/react-menu3/components/SubMenu.tsx +24 -24
- package/src/react-menu3/contexts/EventHandlersContext.ts +2 -2
- package/src/react-menu3/contexts/HoverItemContext.ts +1 -1
- package/src/react-menu3/contexts/ItemSettingsContext.ts +1 -1
- package/src/react-menu3/contexts/MenuListContext.ts +2 -2
- package/src/react-menu3/contexts/MenuListItemContext.ts +2 -2
- package/src/react-menu3/contexts/RadioGroupContext.ts +2 -2
- package/src/react-menu3/contexts/SettingsContext.ts +2 -2
- package/src/react-menu3/hooks/index.ts +9 -9
- package/src/react-menu3/hooks/useBEM.ts +4 -4
- package/src/react-menu3/hooks/useCombinedRef.ts +2 -2
- package/src/react-menu3/hooks/useIsomorphicLayoutEffect.ts +4 -4
- package/src/react-menu3/hooks/useItemEffect.ts +3 -3
- package/src/react-menu3/hooks/useItemState.ts +5 -5
- package/src/react-menu3/hooks/useItems.ts +8 -8
- package/src/react-menu3/hooks/useMenuChange.ts +3 -3
- package/src/react-menu3/hooks/useMenuState.ts +5 -5
- package/src/react-menu3/hooks/useMenuStateAndFocus.ts +4 -4
- package/src/react-menu3/index.ts +11 -11
- package/src/react-menu3/positionUtils/getPositionHelpers.ts +2 -2
- package/src/react-menu3/positionUtils/index.ts +3 -3
- package/src/react-menu3/positionUtils/placeArrowHorizontal.ts +1 -1
- package/src/react-menu3/positionUtils/placeArrowVertical.ts +1 -1
- package/src/react-menu3/positionUtils/placeLeftorRight.ts +13 -13
- package/src/react-menu3/positionUtils/placeToporBottom.ts +15 -15
- package/src/react-menu3/positionUtils/positionContextMenu.ts +4 -4
- package/src/react-menu3/positionUtils/positionMenu.ts +14 -14
- package/src/react-menu3/style-utils/index.ts +24 -24
- package/src/react-menu3/types.ts +15 -15
- package/src/react-menu3/utils/constants.ts +33 -33
- package/src/react-menu3/utils/index.ts +3 -4
- package/src/react-menu3/utils/propTypes2.ts +10 -10
- package/src/react-menu3/utils/utils.ts +14 -14
- package/src/react-menu3/utils/withHovering.tsx +3 -3
- package/src/stories/components/ActionButton.stories.tsx +23 -24
- package/src/stories/grid/FormTest.tsx +15 -16
- package/src/stories/grid/GridDragRow.stories.tsx +33 -34
- package/src/stories/grid/GridFilterButtons.stories.tsx +32 -33
- package/src/stories/grid/GridNoRowsOverlay.stories.tsx +9 -10
- package/src/stories/grid/GridNonEditableRow.stories.tsx +40 -41
- package/src/stories/grid/GridPinnedRow.stories.tsx +25 -26
- package/src/stories/grid/GridPopoutContextMenu.stories.tsx +33 -32
- package/src/stories/grid/GridPopoutEditBoolean.stories.tsx +21 -22
- package/src/stories/grid/GridPopoutEditGeneric.stories.tsx +18 -19
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +50 -49
- package/src/stories/grid/GridPopoverEditBearing.stories.tsx +25 -26
- package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +93 -94
- package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +62 -63
- package/src/stories/grid/GridPopoverEditMultiSelectGrid.stories.tsx +28 -28
- package/src/stories/grid/GridReadOnly.stories.tsx +66 -67
- package/src/stories/grid/GridViewList.stories.tsx +37 -38
- package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +37 -38
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +25 -26
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +25 -26
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectGridInteraction.stories.tsx +31 -31
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +47 -48
- package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +44 -45
- package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +19 -20
- package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +21 -22
- package/src/stories/grid/gridFormStatic/GridFormDropDown.stories.tsx +40 -41
- package/src/stories/grid/gridFormStatic/GridFormEditBearing.stories.tsx +14 -15
- package/src/stories/grid/gridFormStatic/GridFormEditBearingCorrection.stories.tsx +14 -15
- package/src/stories/grid/gridFormStatic/GridFormMessage.stories.tsx +10 -11
- package/src/stories/grid/gridFormStatic/GridFormMultiSelect.stories.tsx +20 -21
- package/src/stories/grid/gridFormStatic/GridFormPopoverMenu.stories.tsx +16 -17
- package/src/stories/grid/gridFormStatic/GridFormTextArea.stories.tsx +13 -14
- package/src/stories/grid/gridFormStatic/GridFormTextInput.stories.tsx +13 -14
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +68 -71
- package/src/stories/react-menu/ReactMenu.stories.tsx +26 -26
- package/src/utils/bearing.test.ts +44 -44
- package/src/utils/bearing.ts +20 -20
- package/src/utils/deferredPromise.ts +1 -1
- package/src/utils/storybookTestUtil.ts +2 -2
- package/src/utils/testQuick.ts +15 -14
- package/src/utils/testUtil.ts +31 -36
- package/src/utils/textMatcher.test.ts +9 -9
- package/src/utils/textMatcher.ts +8 -8
- package/src/utils/textValidator.test.ts +56 -56
- package/src/utils/textValidator.ts +11 -11
- package/src/utils/util.test.ts +20 -20
- package/src/utils/util.ts +7 -7
package/dist/step-ag-grid.cjs.js
CHANGED
|
@@ -8,11 +8,43 @@ var lodashEs = require('lodash-es');
|
|
|
8
8
|
var React = require('react');
|
|
9
9
|
var reactDom = require('react-dom');
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* AgGrid checkbox select does not pass clicks within cell but not on the checkbox to checkbox.
|
|
13
|
+
* This passes the event to the checkbox when you click anywhere in the cell.
|
|
14
|
+
*/
|
|
15
|
+
const clickInputWhenContainingCellClicked = (params) => {
|
|
16
|
+
const { data, event, colDef } = params;
|
|
17
|
+
if (!data || !event)
|
|
18
|
+
return;
|
|
19
|
+
const element = event.target;
|
|
20
|
+
// Already handled
|
|
21
|
+
if (element.closest('.GridCell-readonly') ||
|
|
22
|
+
(['BUTTON', 'INPUT'].includes(element?.tagName) && element.closest('.ag-cell-inline-editing'))) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const row = element.closest('[row-id]');
|
|
26
|
+
if (!row)
|
|
27
|
+
return;
|
|
28
|
+
const colId = colDef.colId;
|
|
29
|
+
if (!colId)
|
|
30
|
+
return;
|
|
31
|
+
const clickInput = () => {
|
|
32
|
+
const cell = row.querySelector(`[col-id='${colId}']`);
|
|
33
|
+
if (!cell)
|
|
34
|
+
return;
|
|
35
|
+
const input = cell.querySelector('input, button');
|
|
36
|
+
if (!input)
|
|
37
|
+
return;
|
|
38
|
+
input?.dispatchEvent(event);
|
|
39
|
+
};
|
|
40
|
+
setTimeout(clickInput, 20);
|
|
41
|
+
};
|
|
42
|
+
|
|
11
43
|
/**
|
|
12
44
|
* If loading is true this returns a loading spinner, otherwise it returns its children.
|
|
13
45
|
*/
|
|
14
46
|
const ComponentLoadingWrapper = (props) => {
|
|
15
|
-
return props.loading ? (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 22, divProps: { role:
|
|
47
|
+
return props.loading ? (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 22, divProps: { role: 'status', ['aria-label']: 'Loading', style: { padding: 16 } } })) : (jsxRuntime.jsxs("div", { style: { pointerEvents: props.saving ? 'none' : 'inherit' }, className: props.className, children: [props.saving && jsxRuntime.jsx("div", { className: 'ComponentLoadingWrapper-saveOverlay' }), props.children] }));
|
|
16
48
|
};
|
|
17
49
|
|
|
18
50
|
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
@@ -61,153 +93,160 @@ const GridContext = React.createContext({
|
|
|
61
93
|
gridReady: false,
|
|
62
94
|
gridRenderState: () => null,
|
|
63
95
|
getColDef: () => {
|
|
64
|
-
console.error(
|
|
96
|
+
console.error('no context provider for getColDef');
|
|
65
97
|
return undefined;
|
|
66
98
|
},
|
|
67
99
|
getColumns: () => {
|
|
68
|
-
console.error(
|
|
100
|
+
console.error('no context provider for getColumns');
|
|
69
101
|
return [];
|
|
70
102
|
},
|
|
71
103
|
getColumnIds: () => {
|
|
72
|
-
console.error(
|
|
104
|
+
console.error('no context provider for getColumnIds');
|
|
73
105
|
return [];
|
|
74
106
|
},
|
|
75
107
|
invisibleColumnIds: undefined,
|
|
76
108
|
setInvisibleColumnIds: () => {
|
|
77
|
-
console.error(
|
|
109
|
+
console.error('no context provider for setInvisibleColumnIds');
|
|
78
110
|
},
|
|
79
111
|
prePopupOps: () => {
|
|
80
|
-
console.error(
|
|
112
|
+
console.error('no context provider for prePopupOps');
|
|
81
113
|
},
|
|
82
114
|
postPopupOps: () => {
|
|
83
|
-
console.error(
|
|
115
|
+
console.error('no context provider for prePopupOps');
|
|
84
116
|
},
|
|
85
117
|
externallySelectedItemsAreInSync: false,
|
|
86
118
|
setApis: () => {
|
|
87
|
-
console.error(
|
|
119
|
+
console.error('no context provider for setApis');
|
|
88
120
|
},
|
|
89
121
|
setQuickFilter: () => {
|
|
90
|
-
console.error(
|
|
122
|
+
console.error('no context provider for setQuickFilter');
|
|
91
123
|
},
|
|
92
124
|
selectRowsById: () => {
|
|
93
|
-
console.error(
|
|
125
|
+
console.error('no context provider for selectRows');
|
|
94
126
|
},
|
|
95
127
|
getSelectedRows: () => {
|
|
96
|
-
console.error(
|
|
128
|
+
console.error('no context provider for getSelectedRows');
|
|
97
129
|
return [];
|
|
98
130
|
},
|
|
99
131
|
getFilteredSelectedRows: () => {
|
|
100
|
-
console.error(
|
|
132
|
+
console.error('no context provider for getFilteredSelectedRows');
|
|
101
133
|
return [];
|
|
102
134
|
},
|
|
103
135
|
getSelectedRowIds: () => {
|
|
104
|
-
console.error(
|
|
136
|
+
console.error('no context provider for getSelectedRowIds');
|
|
105
137
|
return [];
|
|
106
138
|
},
|
|
107
139
|
getFilteredSelectedRowIds: () => {
|
|
108
|
-
console.error(
|
|
140
|
+
console.error('no context provider for getFilteredSelectedRowIds');
|
|
109
141
|
return [];
|
|
110
142
|
},
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
111
144
|
selectRowsDiff: async () => {
|
|
112
|
-
console.error(
|
|
145
|
+
console.error('no context provider for selectRowsDiff');
|
|
113
146
|
},
|
|
114
147
|
selectRowsByIdWithFlash: () => {
|
|
115
|
-
console.error(
|
|
148
|
+
console.error('no context provider for selectRowsWithFlash');
|
|
116
149
|
},
|
|
150
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
117
151
|
selectRowsWithFlashDiff: async () => {
|
|
118
|
-
console.error(
|
|
152
|
+
console.error('no context provider for selectRowsWithFlashDiff');
|
|
119
153
|
},
|
|
120
154
|
flashRows: () => {
|
|
121
|
-
console.error(
|
|
155
|
+
console.error('no context provider for flashRows');
|
|
122
156
|
},
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
123
158
|
flashRowsDiff: async () => {
|
|
124
|
-
console.error(
|
|
159
|
+
console.error('no context provider for flashRows');
|
|
125
160
|
},
|
|
161
|
+
// eslint-disable-next-line @typescript-eslint/require-await,@typescript-eslint/no-misused-promises
|
|
126
162
|
focusByRowById: async () => {
|
|
127
|
-
console.error(
|
|
163
|
+
console.error('no context provider for focusByRowById');
|
|
128
164
|
},
|
|
129
165
|
ensureRowVisible: () => {
|
|
130
|
-
console.error(
|
|
166
|
+
console.error('no context provider for ensureRowVisible');
|
|
131
167
|
return true;
|
|
132
168
|
},
|
|
133
169
|
ensureSelectedRowIsVisible: () => {
|
|
134
|
-
console.error(
|
|
170
|
+
console.error('no context provider for ensureSelectedRowIsVisible');
|
|
135
171
|
},
|
|
136
172
|
getFirstRowId: () => {
|
|
137
|
-
console.error(
|
|
173
|
+
console.error('no context provider for getFirstRowId');
|
|
138
174
|
return -1;
|
|
139
175
|
},
|
|
140
176
|
autoSizeColumns: () => {
|
|
141
|
-
console.error(
|
|
177
|
+
console.error('no context provider for autoSizeColumns');
|
|
142
178
|
return null;
|
|
143
179
|
},
|
|
144
180
|
sizeColumnsToFit: () => {
|
|
145
|
-
console.error(
|
|
181
|
+
console.error('no context provider for autoSizeAllColumns');
|
|
146
182
|
return null;
|
|
147
183
|
},
|
|
148
184
|
editingCells: () => {
|
|
149
|
-
console.error(
|
|
185
|
+
console.error('no context provider for editingCells');
|
|
150
186
|
return false;
|
|
151
187
|
},
|
|
152
188
|
cancelEdit: () => {
|
|
153
|
-
console.error(
|
|
189
|
+
console.error('no context provider for cancelEdit');
|
|
154
190
|
},
|
|
155
191
|
startCellEditing: () => {
|
|
156
|
-
console.error(
|
|
192
|
+
console.error('no context provider for startCellEditing');
|
|
157
193
|
},
|
|
158
194
|
stopEditing: () => {
|
|
159
|
-
console.error(
|
|
195
|
+
console.error('no context provider for stopEditing');
|
|
160
196
|
},
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
161
198
|
updatingCells: async () => {
|
|
162
|
-
console.error(
|
|
199
|
+
console.error('no context provider for modifyUpdating');
|
|
163
200
|
return false;
|
|
164
201
|
},
|
|
165
202
|
redrawRows: () => {
|
|
166
|
-
console.error(
|
|
203
|
+
console.error('no context provider for redrawRows');
|
|
167
204
|
},
|
|
168
205
|
setExternallySelectedItemsAreInSync: () => {
|
|
169
|
-
console.error(
|
|
206
|
+
console.error('no context provider for setExternallySelectedItemsAreInSync');
|
|
170
207
|
},
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
171
209
|
waitForExternallySelectedItemsToBeInSync: async () => {
|
|
172
|
-
console.error(
|
|
210
|
+
console.error('no context provider for waitForExternallySelectedItemsToBeInSync');
|
|
173
211
|
},
|
|
174
212
|
addExternalFilter: () => {
|
|
175
|
-
console.error(
|
|
213
|
+
console.error('no context provider for addExternalFilter');
|
|
176
214
|
},
|
|
177
215
|
removeExternalFilter: () => {
|
|
178
|
-
console.error(
|
|
216
|
+
console.error('no context provider for removeExternalFilter');
|
|
179
217
|
},
|
|
180
218
|
isExternalFilterPresent: () => {
|
|
181
|
-
console.error(
|
|
219
|
+
console.error('no context provider for isExternalFilterPresent');
|
|
182
220
|
return false;
|
|
183
221
|
},
|
|
184
222
|
doesExternalFilterPass: () => {
|
|
185
|
-
console.error(
|
|
223
|
+
console.error('no context provider for doesExternalFilterPass');
|
|
186
224
|
return true;
|
|
187
225
|
},
|
|
188
226
|
downloadCsv: () => {
|
|
189
|
-
console.error(
|
|
227
|
+
console.error('no context provider for downloadCsv');
|
|
190
228
|
},
|
|
191
229
|
setOnCellEditingComplete: () => {
|
|
192
|
-
console.error(
|
|
230
|
+
console.error('no context provider for setOnCellEditingComplete');
|
|
193
231
|
},
|
|
194
232
|
showNoRowsOverlay: () => {
|
|
195
|
-
console.error(
|
|
233
|
+
console.error('no context provider for showLoadingOverlay');
|
|
196
234
|
},
|
|
197
235
|
});
|
|
198
236
|
const useGridContext = () => React.useContext(GridContext);
|
|
199
237
|
|
|
200
238
|
const GridUpdatingContext = React.createContext({
|
|
201
239
|
checkUpdating: () => {
|
|
202
|
-
console.error(
|
|
240
|
+
console.error('Missing GridUpdatingContext');
|
|
203
241
|
return false;
|
|
204
242
|
},
|
|
205
243
|
updatingCols: () => {
|
|
206
|
-
console.error(
|
|
244
|
+
console.error('Missing GridUpdatingContext');
|
|
207
245
|
return [];
|
|
208
246
|
},
|
|
247
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
209
248
|
modifyUpdating: async () => {
|
|
210
|
-
console.error(
|
|
249
|
+
console.error('Missing GridUpdatingContext');
|
|
211
250
|
},
|
|
212
251
|
updatedDep: 0,
|
|
213
252
|
});
|
|
@@ -249,196 +288,19 @@ const hasParentClass = function (className, child) {
|
|
|
249
288
|
return false;
|
|
250
289
|
};
|
|
251
290
|
const stringByteLengthIsInvalid = (str, maxBytes) => new TextEncoder().encode(str).length > maxBytes;
|
|
252
|
-
const fnOrVar = (fn, param) => (typeof fn ===
|
|
291
|
+
const fnOrVar = (fn, param) => (typeof fn === 'function' ? fn(param) : fn);
|
|
253
292
|
const sanitiseFileName = (filename) => {
|
|
254
293
|
const valid = filename
|
|
255
294
|
.trim()
|
|
256
|
-
.replaceAll(/(\/|\\)+/g,
|
|
257
|
-
.replaceAll(/\s+/g,
|
|
258
|
-
.replaceAll(/[^\w\-āēīōūĀĒĪŌŪ.]/g,
|
|
259
|
-
const parts = valid.split(
|
|
295
|
+
.replaceAll(/(\/|\\)+/g, '-')
|
|
296
|
+
.replaceAll(/\s+/g, '_')
|
|
297
|
+
.replaceAll(/[^\w\-āēīōūĀĒĪŌŪ.]/g, '');
|
|
298
|
+
const parts = valid.split('.');
|
|
260
299
|
const fileExt = parts.length > 1 ? parts.pop() : undefined;
|
|
261
300
|
// Arbitrary max filename length of 64 chars + extension
|
|
262
301
|
if (!fileExt)
|
|
263
302
|
return valid.slice().slice(0, 64);
|
|
264
|
-
return valid.slice(0, -fileExt.length - 1).slice(0, 64) +
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
const GridLoadingOverlayComponentFr = (props, externalRef) => (jsxRuntime.jsx("div", { ref: externalRef, style: {
|
|
268
|
-
left: 0,
|
|
269
|
-
top: 0,
|
|
270
|
-
bottom: 0,
|
|
271
|
-
right: 0,
|
|
272
|
-
position: "absolute",
|
|
273
|
-
backgroundColor: "rgba(255,255,255,0.5)",
|
|
274
|
-
}, children: jsxRuntime.jsx("div", { style: { height: "100%", position: "relative" }, children: jsxRuntime.jsx("div", { style: { position: "absolute", left: 0, top: props.headerRowHeight, right: 0, bottom: 0 }, children: jsxRuntime.jsx(lui.LuiStatusSpinner, {}) }) }) }));
|
|
275
|
-
const GridLoadingOverlayComponent = React.forwardRef(GridLoadingOverlayComponentFr);
|
|
276
|
-
const GridNoRowsOverlayFr = (props, externalRef) => {
|
|
277
|
-
if (props.loading) {
|
|
278
|
-
return jsxRuntime.jsx(GridLoadingOverlayComponent, { ref: externalRef, headerRowHeight: props.headerRowHeight });
|
|
279
|
-
}
|
|
280
|
-
if (props.rowCount === 0) {
|
|
281
|
-
return jsxRuntime.jsx("div", { ref: externalRef, children: props.noRowsOverlayText ?? "There are currently no rows" });
|
|
282
|
-
}
|
|
283
|
-
if (props.filteredRowCount === 0) {
|
|
284
|
-
return jsxRuntime.jsx("div", { ref: externalRef, children: props.noRowsMatchingOverlayText ?? "All rows have been filtered" });
|
|
285
|
-
}
|
|
286
|
-
return jsxRuntime.jsx("div", { ref: externalRef });
|
|
287
|
-
};
|
|
288
|
-
const GridNoRowsOverlay = React.forwardRef(GridNoRowsOverlayFr);
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Retains last sort order from via <AgGrid postRowSort>.
|
|
292
|
-
* Then applies this sort until next sort column change.
|
|
293
|
-
* Handles stale sort, when you edit a row but don't want to re-sort.
|
|
294
|
-
*/
|
|
295
|
-
const usePostSortRowsHook = ({ setStaleGrid }) => {
|
|
296
|
-
const { redrawRows } = React.useContext(GridContext);
|
|
297
|
-
// On first run we need to init the first backed up sort order
|
|
298
|
-
const initialised = React.useRef(false);
|
|
299
|
-
// Used to detect sort order has changed since last run
|
|
300
|
-
const lastSortOrderHash = React.useRef("");
|
|
301
|
-
// Used to detect if sort order was the same, has the direction changed
|
|
302
|
-
const previousRowSortIndexRef = React.useRef({});
|
|
303
|
-
// stale sort is when there's a sort and user edits a row
|
|
304
|
-
// this applies a class to the div wrapping the grid which in turn adds a * beside the sort arrow
|
|
305
|
-
const sortWasStale = React.useRef(false);
|
|
306
|
-
// Previous col sort is stored and reapplied if the sort direction changes on the same column and the sort was stale
|
|
307
|
-
// As a sort on a stale row should just resort, not change sort direction
|
|
308
|
-
const previousColSort = React.useRef([]);
|
|
309
|
-
const previousQuickFilter = React.useRef("");
|
|
310
|
-
return React.useCallback(({ api, nodes }) => {
|
|
311
|
-
// Grid is destroyed
|
|
312
|
-
if (!api)
|
|
313
|
-
return;
|
|
314
|
-
const previousRowSortIndex = previousRowSortIndexRef.current;
|
|
315
|
-
const hashNode = (node) => {
|
|
316
|
-
return node ? JSON.stringify(node.data) : "";
|
|
317
|
-
};
|
|
318
|
-
const copyCurrentSortSettings = () => api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
|
|
319
|
-
const backupSortOrder = () => {
|
|
320
|
-
for (const x in previousRowSortIndex)
|
|
321
|
-
delete previousRowSortIndex[x];
|
|
322
|
-
nodes.forEach((node, index) => (previousRowSortIndex[`${node.data.id}`] = { index, hash: hashNode(node) }));
|
|
323
|
-
};
|
|
324
|
-
// Check if column is the first sorted column. Note: column is preconfigured to sort its sortIndex is null not 1
|
|
325
|
-
const isFirstSortColumn = (row) => row.sort && [0, null].includes(row.sortIndex ?? null);
|
|
326
|
-
const isSameColumnAndDifferentSort = (col1, col2) => col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
|
|
327
|
-
const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
|
|
328
|
-
const sortNodesByPreviousSort = () => {
|
|
329
|
-
nodes.sort((a, b) => (previousRowSortIndex[`${a.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER) -
|
|
330
|
-
(previousRowSortIndex[`${b.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER));
|
|
331
|
-
};
|
|
332
|
-
// On first load copy the current sort
|
|
333
|
-
if (!initialised.current) {
|
|
334
|
-
initialised.current = true;
|
|
335
|
-
previousColSort.current = copyCurrentSortSettings();
|
|
336
|
-
}
|
|
337
|
-
const newSortOrder = JSON.stringify(copyCurrentSortSettings());
|
|
338
|
-
let sortOrderChanged = newSortOrder != lastSortOrderHash.current;
|
|
339
|
-
const quickFilter = api.getQuickFilter();
|
|
340
|
-
if (previousQuickFilter.current != quickFilter) {
|
|
341
|
-
previousQuickFilter.current = quickFilter ?? "";
|
|
342
|
-
sortOrderChanged = true;
|
|
343
|
-
}
|
|
344
|
-
if (lodashEs.isEmpty(previousRowSortIndex)) {
|
|
345
|
-
backupSortOrder();
|
|
346
|
-
}
|
|
347
|
-
if (sortOrderChanged) {
|
|
348
|
-
const thisFirstCol = copyCurrentSortSettings().find(isFirstSortColumn);
|
|
349
|
-
const previousFirstCol = previousColSort.current.find(isFirstSortColumn);
|
|
350
|
-
// Change to sort can be: (in the context of stale sort do...)
|
|
351
|
-
// - no sort to sorted (do nothing)
|
|
352
|
-
// - asc to desc (resort as asc, and remove stale sort)
|
|
353
|
-
// - desc to no sort (resort as desc, and remove stale sort)
|
|
354
|
-
const wasSortChangedOnSameColumn = previousFirstCol && (!thisFirstCol || isSameColumnAndDifferentSort(previousFirstCol, thisFirstCol));
|
|
355
|
-
// if sort was stale, and we're here, someone has clicked a stale sort order (^*) in the column header
|
|
356
|
-
if (sortWasStale.current && wasSortChangedOnSameColumn) {
|
|
357
|
-
// Sort was an existing priority 1 column
|
|
358
|
-
// We want to re-sort with the old sort direction and clear stale sort
|
|
359
|
-
sortWasStale.current = false;
|
|
360
|
-
setStaleGrid(false);
|
|
361
|
-
// trigger a recapture of sort order
|
|
362
|
-
lastSortOrderHash.current = "";
|
|
363
|
-
restorePreviousSortColumnState();
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
// Sort was on a different column so clear sort and sort like normal
|
|
367
|
-
if (sortWasStale.current) {
|
|
368
|
-
sortWasStale.current = false;
|
|
369
|
-
setStaleGrid(false);
|
|
370
|
-
}
|
|
371
|
-
// Columns were sorted so retain the sort
|
|
372
|
-
backupSortOrder();
|
|
373
|
-
lastSortOrderHash.current = newSortOrder;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
else {
|
|
377
|
-
let firstChangedNodeIndex = -1;
|
|
378
|
-
let lastNewNode = undefined;
|
|
379
|
-
let changedRowCount = 0;
|
|
380
|
-
let newRowCount = 0;
|
|
381
|
-
let index = 0;
|
|
382
|
-
for (const node of nodes) {
|
|
383
|
-
const psr = previousRowSortIndex[`${node.data.id}`];
|
|
384
|
-
if (psr) {
|
|
385
|
-
if (psr.hash != hashNode(node)) {
|
|
386
|
-
if (firstChangedNodeIndex === -1)
|
|
387
|
-
firstChangedNodeIndex = index;
|
|
388
|
-
changedRowCount++;
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
lastNewNode = node;
|
|
393
|
-
newRowCount++;
|
|
394
|
-
}
|
|
395
|
-
index++;
|
|
396
|
-
}
|
|
397
|
-
let wasStale = false;
|
|
398
|
-
if (changedRowCount === 0 && newRowCount === 1) {
|
|
399
|
-
// insert new row at end
|
|
400
|
-
const newIndex = index - 1;
|
|
401
|
-
previousRowSortIndex[`${lastNewNode?.data.id}`] = { index: newIndex, hash: hashNode(lastNewNode) };
|
|
402
|
-
wasStale = true;
|
|
403
|
-
}
|
|
404
|
-
else if (changedRowCount === 2 && newRowCount === 0) {
|
|
405
|
-
// This must be a swap rows (sometimes it's not, needs further attention)
|
|
406
|
-
backupSortOrder();
|
|
407
|
-
wasStale = false;
|
|
408
|
-
}
|
|
409
|
-
else if (changedRowCount > 1 && newRowCount === 1) {
|
|
410
|
-
// This must be a insert so, insert new row near the row that changed
|
|
411
|
-
previousRowSortIndex[`${lastNewNode?.data.id}`] = {
|
|
412
|
-
index: firstChangedNodeIndex + 0.5,
|
|
413
|
-
hash: hashNode(lastNewNode),
|
|
414
|
-
};
|
|
415
|
-
wasStale = true;
|
|
416
|
-
// For some reason AgGrid mis-positions the inserted row.
|
|
417
|
-
lastNewNode && redrawRows();
|
|
418
|
-
}
|
|
419
|
-
else if (changedRowCount == 1 && newRowCount === 0) {
|
|
420
|
-
// User edited one row so, do nothing, retain sort
|
|
421
|
-
wasStale = true;
|
|
422
|
-
}
|
|
423
|
-
else if (changedRowCount !== 0 || newRowCount != 0) {
|
|
424
|
-
// too many rows changed, resort
|
|
425
|
-
backupSortOrder();
|
|
426
|
-
}
|
|
427
|
-
if (wasStale) {
|
|
428
|
-
// Check if the sort order the aggrid passed matches our stale sort order
|
|
429
|
-
const stillStale = Object.keys(previousRowSortIndex).length != nodes.length ||
|
|
430
|
-
nodes.some((node, index) => previousRowSortIndex[`${node.data.id}`]?.index !== index);
|
|
431
|
-
// If we haven't already processed a stale sort then...
|
|
432
|
-
if (stillStale && !sortWasStale.current) {
|
|
433
|
-
// backup sort state, so we can restore it when sort is clicked on a stale column
|
|
434
|
-
previousColSort.current = copyCurrentSortSettings();
|
|
435
|
-
sortWasStale.current = true;
|
|
436
|
-
setStaleGrid(true);
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
sortNodesByPreviousSort();
|
|
440
|
-
}
|
|
441
|
-
}, [redrawRows, setStaleGrid]);
|
|
303
|
+
return valid.slice(0, -fileExt.length - 1).slice(0, 64) + '.' + fileExt;
|
|
442
304
|
};
|
|
443
305
|
|
|
444
306
|
/**
|
|
@@ -454,9 +316,9 @@ const GridHeaderSelect = ({ api }) => {
|
|
|
454
316
|
const clickHandler = () => {
|
|
455
317
|
setUpdateCounter(updateCounter + 1);
|
|
456
318
|
};
|
|
457
|
-
api.addEventListener(
|
|
319
|
+
api.addEventListener('selectionChanged', clickHandler);
|
|
458
320
|
return () => {
|
|
459
|
-
!api.isDestroyed() && api.removeEventListener(
|
|
321
|
+
!api.isDestroyed() && api.removeEventListener('selectionChanged', clickHandler);
|
|
460
322
|
};
|
|
461
323
|
}, [api, updateCounter]);
|
|
462
324
|
const handleMultiSelect = () => {
|
|
@@ -470,11 +332,23 @@ const GridHeaderSelect = ({ api }) => {
|
|
|
470
332
|
const totalNodeCount = api.getDisplayedRowCount();
|
|
471
333
|
const partialSelect = selectedNodeCount != 0 && selectedNodeCount != totalNodeCount;
|
|
472
334
|
const allSelected = selectedNodeCount != 0 && selectedNodeCount == totalNodeCount;
|
|
473
|
-
return (jsxRuntime.jsx("div", { className: clsx(
|
|
335
|
+
return (jsxRuntime.jsx("div", { className: clsx('ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper', partialSelect && 'ag-indeterminate', allSelected && 'ag-checked'), onClick: handleMultiSelect, children: jsxRuntime.jsx("input", { type: "checkbox", className: 'ag-checkbox-input-wrapper', onChange: () => {
|
|
474
336
|
/* do nothing */
|
|
475
337
|
} }) }));
|
|
476
338
|
};
|
|
477
339
|
|
|
340
|
+
const EventHandlersContext = React.createContext({
|
|
341
|
+
handleClick: () => { },
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
const ItemSettingsContext = React.createContext({
|
|
345
|
+
submenuOpenDelay: 0,
|
|
346
|
+
submenuCloseDelay: 0,
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// FIXME hacking a default context in here is probably bad, but the context is mess
|
|
350
|
+
const SettingsContext = React.createContext({});
|
|
351
|
+
|
|
478
352
|
// Generate className following BEM methodology: http://getbem.com/naming/
|
|
479
353
|
// Modifier value can be one of the following types: boolean, string, undefined
|
|
480
354
|
const useBEM = ({ block, element, modifiers, className }) => React.useMemo(() => {
|
|
@@ -486,8 +360,8 @@ const useBEM = ({ block, element, modifiers, className }) => React.useMemo(() =>
|
|
|
486
360
|
if (value)
|
|
487
361
|
classString += ` ${blockElement}--${value === true ? name : `${name}-${value}`}`;
|
|
488
362
|
});
|
|
489
|
-
let expandedClassName = typeof className ===
|
|
490
|
-
if (typeof expandedClassName ===
|
|
363
|
+
let expandedClassName = typeof className === 'function' ? className(modifiers) : className;
|
|
364
|
+
if (typeof expandedClassName === 'string') {
|
|
491
365
|
expandedClassName = expandedClassName.trim();
|
|
492
366
|
if (expandedClassName)
|
|
493
367
|
classString += ` ${expandedClassName}`;
|
|
@@ -498,7 +372,7 @@ const useBEM = ({ block, element, modifiers, className }) => React.useMemo(() =>
|
|
|
498
372
|
// Adapted from material-ui
|
|
499
373
|
// https://github.com/mui-org/material-ui/blob/f996027d00e7e4bff3fc040786c1706f9c6c3f82/packages/material-ui-utils/src/useForkRef.ts
|
|
500
374
|
const setRef = (ref, instance) => {
|
|
501
|
-
if (typeof ref ===
|
|
375
|
+
if (typeof ref === 'function') {
|
|
502
376
|
ref(instance);
|
|
503
377
|
}
|
|
504
378
|
else if (ref) {
|
|
@@ -518,33 +392,50 @@ const useCombinedRef = (refA, refB) => {
|
|
|
518
392
|
// https://github.com/reduxjs/react-redux/blob/b48d087d76f666e1c6c5a9713bbec112a1631841/src/utils/useIsomorphicLayoutEffect.js#L12
|
|
519
393
|
// https://gist.github.com/gaearon/e7d97cdf38a2907924ea12e4ebdf3c85
|
|
520
394
|
// https://github.com/facebook/react/issues/14927#issuecomment-549457471
|
|
521
|
-
const useIsomorphicLayoutEffect = typeof window !==
|
|
522
|
-
typeof window.document !==
|
|
523
|
-
typeof window.document.createElement !==
|
|
395
|
+
const useIsomorphicLayoutEffect = typeof window !== 'undefined' &&
|
|
396
|
+
typeof window.document !== 'undefined' &&
|
|
397
|
+
typeof window.document.createElement !== 'undefined'
|
|
524
398
|
? React.useLayoutEffect
|
|
525
399
|
: React.useEffect;
|
|
526
400
|
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const
|
|
401
|
+
const useItemEffect = (isDisabled, menuItemRef, updateItems) => {
|
|
402
|
+
useIsomorphicLayoutEffect(() => {
|
|
403
|
+
if (!menuItemRef)
|
|
404
|
+
return;
|
|
405
|
+
if (process.env.NODE_ENV !== 'production' && !updateItems) {
|
|
406
|
+
throw new Error(`[React-Menu] This menu item or submenu should be rendered under a menu: ${menuItemRef.current.outerHTML}`);
|
|
407
|
+
}
|
|
408
|
+
if (isDisabled)
|
|
409
|
+
return;
|
|
410
|
+
const item = menuItemRef.current;
|
|
411
|
+
updateItems(item, true);
|
|
412
|
+
return () => {
|
|
413
|
+
updateItems(item);
|
|
414
|
+
};
|
|
415
|
+
}, [isDisabled, menuItemRef, updateItems]);
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
const menuContainerClass = 'szh-menu-container';
|
|
419
|
+
const menuClass = 'szh-menu';
|
|
420
|
+
const menuButtonClass = 'szh-menu-button';
|
|
421
|
+
const menuArrowClass = 'arrow';
|
|
422
|
+
const menuItemClass = 'item';
|
|
423
|
+
const menuDividerClass = 'divider';
|
|
424
|
+
const menuHeaderClass = 'header';
|
|
425
|
+
const menuGroupClass = 'group';
|
|
426
|
+
const subMenuClass = 'submenu';
|
|
427
|
+
const radioGroupClass = 'radio-group';
|
|
537
428
|
const Keys = Object.freeze({
|
|
538
|
-
ENTER:
|
|
539
|
-
TAB:
|
|
540
|
-
ESC:
|
|
541
|
-
SPACE:
|
|
542
|
-
HOME:
|
|
543
|
-
END:
|
|
544
|
-
LEFT:
|
|
545
|
-
RIGHT:
|
|
546
|
-
UP:
|
|
547
|
-
DOWN:
|
|
429
|
+
ENTER: 'Enter',
|
|
430
|
+
TAB: 'Tab',
|
|
431
|
+
ESC: 'Escape',
|
|
432
|
+
SPACE: ' ',
|
|
433
|
+
HOME: 'Home',
|
|
434
|
+
END: 'End',
|
|
435
|
+
LEFT: 'ArrowLeft',
|
|
436
|
+
RIGHT: 'ArrowRight',
|
|
437
|
+
UP: 'ArrowUp',
|
|
438
|
+
DOWN: 'ArrowDown',
|
|
548
439
|
});
|
|
549
440
|
const HoverActionTypes = Object.freeze({
|
|
550
441
|
RESET: 0,
|
|
@@ -557,39 +448,39 @@ const HoverActionTypes = Object.freeze({
|
|
|
557
448
|
SET_INDEX: 7,
|
|
558
449
|
});
|
|
559
450
|
const CloseReason = Object.freeze({
|
|
560
|
-
CLICK:
|
|
561
|
-
CANCEL:
|
|
562
|
-
BLUR:
|
|
563
|
-
SCROLL:
|
|
564
|
-
TAB_FORWARD:
|
|
565
|
-
TAB_BACKWARD:
|
|
451
|
+
CLICK: 'click',
|
|
452
|
+
CANCEL: 'cancel',
|
|
453
|
+
BLUR: 'blur',
|
|
454
|
+
SCROLL: 'scroll',
|
|
455
|
+
TAB_FORWARD: 'tab_forward',
|
|
456
|
+
TAB_BACKWARD: 'tab_backward',
|
|
566
457
|
});
|
|
567
458
|
const FocusPositions = Object.freeze({
|
|
568
|
-
FIRST:
|
|
569
|
-
LAST:
|
|
459
|
+
FIRST: 'first',
|
|
460
|
+
LAST: 'last',
|
|
570
461
|
});
|
|
571
462
|
const MenuStateMap = Object.freeze({
|
|
572
|
-
entering:
|
|
573
|
-
entered:
|
|
574
|
-
exiting:
|
|
575
|
-
exited:
|
|
463
|
+
entering: 'opening',
|
|
464
|
+
entered: 'open',
|
|
465
|
+
exiting: 'closing',
|
|
466
|
+
exited: 'closed',
|
|
576
467
|
});
|
|
577
468
|
|
|
578
|
-
const isMenuOpen = (state) => !!state && state[0] ===
|
|
469
|
+
const isMenuOpen = (state) => !!state && state[0] === 'o';
|
|
579
470
|
const batchedUpdates = reactDom.unstable_batchedUpdates || ((callback) => callback());
|
|
580
471
|
const floatEqual = (a, b, diff = 0.0001) => Math.abs(a - b) < diff;
|
|
581
472
|
const getTransition = (transition, name) => transition === true || !!(transition && transition[name]);
|
|
582
473
|
function safeCall(fn, arg) {
|
|
583
|
-
return typeof fn ===
|
|
474
|
+
return typeof fn === 'function' ? fn(arg) : fn;
|
|
584
475
|
}
|
|
585
|
-
const internalKey =
|
|
476
|
+
const internalKey = '_szhsinMenu';
|
|
586
477
|
const getName = (component) => component[internalKey];
|
|
587
478
|
const mergeProps = (target, source) => {
|
|
588
479
|
source &&
|
|
589
480
|
Object.keys(source).forEach((key) => {
|
|
590
481
|
const targetProp = target[key];
|
|
591
482
|
const sourceProp = source[key];
|
|
592
|
-
if (typeof sourceProp ===
|
|
483
|
+
if (typeof sourceProp === 'function' && targetProp) {
|
|
593
484
|
target[key] = (...arg) => {
|
|
594
485
|
sourceProp(...arg);
|
|
595
486
|
targetProp(...arg);
|
|
@@ -631,24 +522,24 @@ const getScrollAncestor = (node) => {
|
|
|
631
522
|
};
|
|
632
523
|
function commonProps(isDisabled, isHovering) {
|
|
633
524
|
return {
|
|
634
|
-
|
|
525
|
+
'aria-disabled': isDisabled || undefined,
|
|
635
526
|
tabIndex: isHovering ? 0 : -1,
|
|
636
527
|
};
|
|
637
528
|
}
|
|
638
529
|
const indexOfNode = (nodeList, node) => lodashEs.findIndex(nodeList, node);
|
|
639
530
|
const focusFirstInput = (container) => {
|
|
640
531
|
// We can't use instanceof Element in portals, so I use querySelectorAll as a proxy here
|
|
641
|
-
if (!container || !(
|
|
532
|
+
if (!container || !('querySelectorAll' in container))
|
|
642
533
|
return false;
|
|
643
534
|
const inputs = container.querySelectorAll("input[type='text'],input:not([type]),textarea");
|
|
644
535
|
const input = inputs[0];
|
|
645
536
|
// Using focus as proxy for HTMLElement
|
|
646
|
-
if (!input || !(
|
|
537
|
+
if (!input || !('focus' in input))
|
|
647
538
|
return false;
|
|
648
539
|
input.focus();
|
|
649
540
|
// Text areas should start at end
|
|
650
541
|
// this is a proxy for instanceof HTMLTextAreaElement
|
|
651
|
-
if ([
|
|
542
|
+
if (['textarea', 'text'].includes(input.type)) {
|
|
652
543
|
input.setSelectionRange(0, input.value.length);
|
|
653
544
|
}
|
|
654
545
|
return true;
|
|
@@ -700,7 +591,7 @@ const useItems = (menuRef, focusRef) => {
|
|
|
700
591
|
const sortItems = () => {
|
|
701
592
|
if (mutableState.sorted)
|
|
702
593
|
return;
|
|
703
|
-
const orderedNodes = menuRef.current.querySelectorAll(
|
|
594
|
+
const orderedNodes = menuRef.current.querySelectorAll('.szh-menu__item');
|
|
704
595
|
items.sort((a, b) => indexOfNode(orderedNodes, a) - indexOfNode(orderedNodes, b));
|
|
705
596
|
mutableState.sorted = true;
|
|
706
597
|
};
|
|
@@ -727,12 +618,12 @@ const useItems = (menuRef, focusRef) => {
|
|
|
727
618
|
newItem = items[index];
|
|
728
619
|
break;
|
|
729
620
|
case HoverActionTypes.SET_INDEX:
|
|
730
|
-
if (typeof nextIndex !==
|
|
621
|
+
if (typeof nextIndex !== 'number')
|
|
731
622
|
break;
|
|
732
623
|
sortItems();
|
|
733
624
|
index = nextIndex;
|
|
734
625
|
newItem = items[index];
|
|
735
|
-
lodashEs.defer(() => newItem.scrollIntoView({ behavior:
|
|
626
|
+
lodashEs.defer(() => newItem.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' }));
|
|
736
627
|
break;
|
|
737
628
|
case HoverActionTypes.INCREASE:
|
|
738
629
|
sortItems();
|
|
@@ -758,7 +649,7 @@ const useItems = (menuRef, focusRef) => {
|
|
|
758
649
|
break;
|
|
759
650
|
}
|
|
760
651
|
default:
|
|
761
|
-
if (process.env.NODE_ENV !==
|
|
652
|
+
if (process.env.NODE_ENV !== 'production')
|
|
762
653
|
throw new Error(`[React-Menu] Unknown hover action type: ${actionType}`);
|
|
763
654
|
}
|
|
764
655
|
if (!newItem && !newItemFn)
|
|
@@ -769,28 +660,6 @@ const useItems = (menuRef, focusRef) => {
|
|
|
769
660
|
return { hoverItem, dispatch, updateItems };
|
|
770
661
|
};
|
|
771
662
|
|
|
772
|
-
const useItemEffect = (isDisabled, menuItemRef, updateItems) => {
|
|
773
|
-
useIsomorphicLayoutEffect(() => {
|
|
774
|
-
if (!menuItemRef)
|
|
775
|
-
return;
|
|
776
|
-
if (process.env.NODE_ENV !== "production" && !updateItems) {
|
|
777
|
-
throw new Error(`[React-Menu] This menu item or submenu should be rendered under a menu: ${menuItemRef.current.outerHTML}`);
|
|
778
|
-
}
|
|
779
|
-
if (isDisabled)
|
|
780
|
-
return;
|
|
781
|
-
const item = menuItemRef.current;
|
|
782
|
-
updateItems(item, true);
|
|
783
|
-
return () => {
|
|
784
|
-
updateItems(item);
|
|
785
|
-
};
|
|
786
|
-
}, [isDisabled, menuItemRef, updateItems]);
|
|
787
|
-
};
|
|
788
|
-
|
|
789
|
-
const ItemSettingsContext = React.createContext({
|
|
790
|
-
submenuOpenDelay: 0,
|
|
791
|
-
submenuCloseDelay: 0,
|
|
792
|
-
});
|
|
793
|
-
|
|
794
663
|
const MenuListItemContext = React.createContext({
|
|
795
664
|
dispatch: () => { },
|
|
796
665
|
updateItems: () => { },
|
|
@@ -958,8 +827,8 @@ const useMenuState = (props) => {
|
|
|
958
827
|
mountOnEnter: !initialMounted,
|
|
959
828
|
unmountOnExit: unmountOnClose,
|
|
960
829
|
timeout: transitionTimeout ?? 500,
|
|
961
|
-
enter: getTransition(transition,
|
|
962
|
-
exit: getTransition(transition,
|
|
830
|
+
enter: getTransition(transition, 'open'),
|
|
831
|
+
exit: getTransition(transition, 'close'),
|
|
963
832
|
});
|
|
964
833
|
return [{ state: MenuStateMap[state.status], endTransition }, toggleMenu];
|
|
965
834
|
};
|
|
@@ -974,18 +843,6 @@ const useMenuStateAndFocus = (options) => {
|
|
|
974
843
|
return [{ menuItemFocus, ...menuProps }, toggleMenu, openMenu];
|
|
975
844
|
};
|
|
976
845
|
|
|
977
|
-
const MenuButton = React.forwardRef(function MenuButton({ className, isOpen, disabled, children, ...restProps }, ref) {
|
|
978
|
-
const modifiers = React.useMemo(() => ({ open: isOpen }), [isOpen]);
|
|
979
|
-
return (jsxRuntime.jsx("button", { "aria-haspopup": true, "aria-expanded": isOpen, "aria-disabled": disabled || undefined, type: "button", disabled: disabled, ...restProps, ref: ref, className: useBEM({ block: menuButtonClass, modifiers, className }), children: children }));
|
|
980
|
-
});
|
|
981
|
-
|
|
982
|
-
const EventHandlersContext = React.createContext({
|
|
983
|
-
handleClick: () => { },
|
|
984
|
-
});
|
|
985
|
-
|
|
986
|
-
// FIXME hacking a default context in here is probably bad, but the context is mess
|
|
987
|
-
const SettingsContext = React.createContext({});
|
|
988
|
-
|
|
989
846
|
const MenuListContext = React.createContext({});
|
|
990
847
|
|
|
991
848
|
const getPositionHelpers = (containerRef, menuRef, menuScroll, boundingBoxPadding) => {
|
|
@@ -1080,14 +937,14 @@ const positionContextMenu = ({ positionHelpers, anchorPoint, }) => {
|
|
|
1080
937
|
x = confineHorizontally(x);
|
|
1081
938
|
}
|
|
1082
939
|
// Similar logic to the left and right side above.
|
|
1083
|
-
let computedDirection =
|
|
940
|
+
let computedDirection = 'bottom';
|
|
1084
941
|
const bottomOverflow = getBottomOverflow(y);
|
|
1085
942
|
if (bottomOverflow > 0) {
|
|
1086
943
|
const adjustedY = y - menuRect.height;
|
|
1087
944
|
const topOverflow = getTopOverflow(adjustedY);
|
|
1088
945
|
if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
|
|
1089
946
|
y = adjustedY;
|
|
1090
|
-
computedDirection =
|
|
947
|
+
computedDirection = 'top';
|
|
1091
948
|
}
|
|
1092
949
|
y = confineVertically(y);
|
|
1093
950
|
}
|
|
@@ -1106,18 +963,18 @@ const placeLeftorRight = (props) => {
|
|
|
1106
963
|
const { anchorRect, containerRect, menuRect, placeLeftorRightY, placeLeftX, placeRightX, getLeftOverflow, getRightOverflow, confineHorizontally, confineVertically, arrowRef, arrow, direction, position, } = props;
|
|
1107
964
|
let computedDirection = direction;
|
|
1108
965
|
let y = placeLeftorRightY;
|
|
1109
|
-
if (position !==
|
|
966
|
+
if (position !== 'initial') {
|
|
1110
967
|
y = confineVertically(y);
|
|
1111
|
-
if (position ===
|
|
968
|
+
if (position === 'anchor') {
|
|
1112
969
|
// restrict menu to the edge of anchor element
|
|
1113
970
|
y = Math.min(y, anchorRect.bottom - containerRect.top);
|
|
1114
971
|
y = Math.max(y, anchorRect.top - containerRect.top - menuRect.height);
|
|
1115
972
|
}
|
|
1116
973
|
}
|
|
1117
974
|
let x, leftOverflow, rightOverflow;
|
|
1118
|
-
if (computedDirection ===
|
|
975
|
+
if (computedDirection === 'left') {
|
|
1119
976
|
x = placeLeftX;
|
|
1120
|
-
if (position !==
|
|
977
|
+
if (position !== 'initial') {
|
|
1121
978
|
// if menu overflows to the left,
|
|
1122
979
|
// try to reposition it to the right of the anchor.
|
|
1123
980
|
leftOverflow = getLeftOverflow(x);
|
|
@@ -1127,7 +984,7 @@ const placeLeftorRight = (props) => {
|
|
|
1127
984
|
rightOverflow = getRightOverflow(placeRightX);
|
|
1128
985
|
if (rightOverflow <= 0 || -leftOverflow > rightOverflow) {
|
|
1129
986
|
x = placeRightX;
|
|
1130
|
-
computedDirection =
|
|
987
|
+
computedDirection = 'right';
|
|
1131
988
|
}
|
|
1132
989
|
}
|
|
1133
990
|
}
|
|
@@ -1135,18 +992,18 @@ const placeLeftorRight = (props) => {
|
|
|
1135
992
|
else {
|
|
1136
993
|
// Opposite logic to the 'left' direction above
|
|
1137
994
|
x = placeRightX;
|
|
1138
|
-
if (position !==
|
|
995
|
+
if (position !== 'initial') {
|
|
1139
996
|
rightOverflow = getRightOverflow(x);
|
|
1140
997
|
if (rightOverflow > 0) {
|
|
1141
998
|
leftOverflow = getLeftOverflow(placeLeftX);
|
|
1142
999
|
if (leftOverflow >= 0 || -leftOverflow < rightOverflow) {
|
|
1143
1000
|
x = placeLeftX;
|
|
1144
|
-
computedDirection =
|
|
1001
|
+
computedDirection = 'left';
|
|
1145
1002
|
}
|
|
1146
1003
|
}
|
|
1147
1004
|
}
|
|
1148
1005
|
}
|
|
1149
|
-
if (position ===
|
|
1006
|
+
if (position === 'auto')
|
|
1150
1007
|
x = confineHorizontally(x);
|
|
1151
1008
|
const arrowY = arrow
|
|
1152
1009
|
? placeArrowVertical({
|
|
@@ -1171,20 +1028,20 @@ const placeArrowHorizontal = (p) => {
|
|
|
1171
1028
|
const placeToporBottom = (props) => {
|
|
1172
1029
|
const { anchorRect, containerRect, menuRect, placeToporBottomX, placeTopY, placeBottomY, getTopOverflow, getBottomOverflow, confineHorizontally, confineVertically, arrowRef, arrow, direction, position, } = props;
|
|
1173
1030
|
// make sure invalid direction is treated as 'bottom'
|
|
1174
|
-
let computedDirection = direction ===
|
|
1031
|
+
let computedDirection = direction === 'top' ? 'top' : 'bottom';
|
|
1175
1032
|
let x = placeToporBottomX;
|
|
1176
|
-
if (position !==
|
|
1033
|
+
if (position !== 'initial') {
|
|
1177
1034
|
x = confineHorizontally(x);
|
|
1178
|
-
if (position ===
|
|
1035
|
+
if (position === 'anchor') {
|
|
1179
1036
|
// restrict menu to the edge of anchor element
|
|
1180
1037
|
x = Math.min(x, anchorRect.right - containerRect.left);
|
|
1181
1038
|
x = Math.max(x, anchorRect.left - containerRect.left - menuRect.width);
|
|
1182
1039
|
}
|
|
1183
1040
|
}
|
|
1184
1041
|
let y, topOverflow, bottomOverflow;
|
|
1185
|
-
if (computedDirection ===
|
|
1042
|
+
if (computedDirection === 'top') {
|
|
1186
1043
|
y = placeTopY;
|
|
1187
|
-
if (position !==
|
|
1044
|
+
if (position !== 'initial') {
|
|
1188
1045
|
// if menu overflows to the top,
|
|
1189
1046
|
// try to reposition it to the bottom of the anchor.
|
|
1190
1047
|
topOverflow = getTopOverflow(y);
|
|
@@ -1194,7 +1051,7 @@ const placeToporBottom = (props) => {
|
|
|
1194
1051
|
bottomOverflow = getBottomOverflow(placeBottomY);
|
|
1195
1052
|
if (bottomOverflow <= 0 || -topOverflow > bottomOverflow) {
|
|
1196
1053
|
y = placeBottomY;
|
|
1197
|
-
computedDirection =
|
|
1054
|
+
computedDirection = 'bottom';
|
|
1198
1055
|
}
|
|
1199
1056
|
}
|
|
1200
1057
|
}
|
|
@@ -1202,18 +1059,18 @@ const placeToporBottom = (props) => {
|
|
|
1202
1059
|
else {
|
|
1203
1060
|
// Opposite logic to the 'top' direction above
|
|
1204
1061
|
y = placeBottomY;
|
|
1205
|
-
if (position !==
|
|
1062
|
+
if (position !== 'initial') {
|
|
1206
1063
|
bottomOverflow = getBottomOverflow(y);
|
|
1207
1064
|
if (bottomOverflow > 0) {
|
|
1208
1065
|
topOverflow = getTopOverflow(placeTopY);
|
|
1209
1066
|
if (topOverflow >= 0 || -topOverflow < bottomOverflow) {
|
|
1210
1067
|
y = placeTopY;
|
|
1211
|
-
computedDirection =
|
|
1068
|
+
computedDirection = 'top';
|
|
1212
1069
|
}
|
|
1213
1070
|
}
|
|
1214
1071
|
}
|
|
1215
1072
|
}
|
|
1216
|
-
if (position ===
|
|
1073
|
+
if (position === 'auto')
|
|
1217
1074
|
y = confineVertically(y);
|
|
1218
1075
|
const arrowX = arrow
|
|
1219
1076
|
? placeArrowHorizontal({
|
|
@@ -1233,7 +1090,7 @@ const positionMenu = (props) => {
|
|
|
1233
1090
|
let horizontalOffset = offsetX;
|
|
1234
1091
|
let verticalOffset = offsetY;
|
|
1235
1092
|
if (arrow && arrowRef.current) {
|
|
1236
|
-
if (direction ===
|
|
1093
|
+
if (direction === 'left' || direction === 'right') {
|
|
1237
1094
|
horizontalOffset += arrowRef.current.offsetWidth;
|
|
1238
1095
|
}
|
|
1239
1096
|
else {
|
|
@@ -1248,11 +1105,11 @@ const positionMenu = (props) => {
|
|
|
1248
1105
|
const placeTopY = anchorRect.top - containerRect.top - menuRect.height - verticalOffset;
|
|
1249
1106
|
const placeBottomY = anchorRect.bottom - containerRect.top + verticalOffset;
|
|
1250
1107
|
let placeToporBottomX, placeLeftorRightY;
|
|
1251
|
-
if (align ===
|
|
1108
|
+
if (align === 'end') {
|
|
1252
1109
|
placeToporBottomX = anchorRect.right - containerRect.left - menuRect.width;
|
|
1253
1110
|
placeLeftorRightY = anchorRect.bottom - containerRect.top - menuRect.height;
|
|
1254
1111
|
}
|
|
1255
|
-
else if (align ===
|
|
1112
|
+
else if (align === 'center') {
|
|
1256
1113
|
placeToporBottomX = anchorRect.left - containerRect.left - (menuRect.width - anchorRect.width) / 2;
|
|
1257
1114
|
placeLeftorRightY = anchorRect.top - containerRect.top - (menuRect.height - anchorRect.height) / 2;
|
|
1258
1115
|
}
|
|
@@ -1277,17 +1134,17 @@ const positionMenu = (props) => {
|
|
|
1277
1134
|
position,
|
|
1278
1135
|
};
|
|
1279
1136
|
switch (direction) {
|
|
1280
|
-
case
|
|
1281
|
-
case
|
|
1137
|
+
case 'left':
|
|
1138
|
+
case 'right':
|
|
1282
1139
|
return placeLeftorRight(options);
|
|
1283
|
-
case
|
|
1284
|
-
case
|
|
1140
|
+
case 'top':
|
|
1141
|
+
case 'bottom':
|
|
1285
1142
|
default:
|
|
1286
1143
|
return placeToporBottom(options);
|
|
1287
1144
|
}
|
|
1288
1145
|
};
|
|
1289
1146
|
|
|
1290
|
-
const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowStyle, anchorPoint, anchorRef, containerRef, externalRef, parentScrollingRef, arrow, align =
|
|
1147
|
+
const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowStyle, anchorPoint, anchorRef, containerRef, externalRef, parentScrollingRef, arrow, align = 'start', direction = 'bottom', position = 'auto', overflow = 'visible', setDownOverflow, repositionFlag, captureFocus = true, state, endTransition, isDisabled, menuItemFocus, dontShrinkIfDirectionIsTop, offsetX = 0, offsetY = 0, children, onClose, ...restProps }) => {
|
|
1291
1148
|
const [menuPosition, setMenuPosition] = React.useState({ x: 0, y: 0 });
|
|
1292
1149
|
const [arrowPosition, setArrowPosition] = React.useState({ x: 0, y: 0 });
|
|
1293
1150
|
const [overflowData, setOverflowData] = React.useState();
|
|
@@ -1305,8 +1162,8 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1305
1162
|
const latestHandlePosition = React.useRef(() => { });
|
|
1306
1163
|
const { hoverItem, dispatch, updateItems } = useItems(menuRef, focusRef);
|
|
1307
1164
|
const isOpen = isMenuOpen(state);
|
|
1308
|
-
const openTransition = getTransition(transition,
|
|
1309
|
-
const closeTransition = getTransition(transition,
|
|
1165
|
+
const openTransition = getTransition(transition, 'open');
|
|
1166
|
+
const closeTransition = getTransition(transition, 'close');
|
|
1310
1167
|
const scrollNodes = scrollNodesRef.current;
|
|
1311
1168
|
/**
|
|
1312
1169
|
* Given the menu-item we are on, find the closest or furthest next menu-item horizontally and focus it.
|
|
@@ -1316,8 +1173,8 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1316
1173
|
if (!menuItemEl)
|
|
1317
1174
|
return false;
|
|
1318
1175
|
let [best, worst] = [];
|
|
1319
|
-
findParentWithClass(
|
|
1320
|
-
?.querySelectorAll(
|
|
1176
|
+
findParentWithClass('szh-menu', menuItemEl)
|
|
1177
|
+
?.querySelectorAll('.szh-menu__item')
|
|
1321
1178
|
?.forEach((item, i) => {
|
|
1322
1179
|
// Must be at same height as currently focused menu-item
|
|
1323
1180
|
if (item.offsetTop === menuItemEl.offsetTop) {
|
|
@@ -1332,14 +1189,14 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1332
1189
|
const r = best ?? worst;
|
|
1333
1190
|
if (!r)
|
|
1334
1191
|
return false;
|
|
1335
|
-
dispatch(HoverActionTypes.SET_INDEX, undefined, r[
|
|
1192
|
+
dispatch(HoverActionTypes.SET_INDEX, undefined, r['i']);
|
|
1336
1193
|
return true;
|
|
1337
1194
|
};
|
|
1338
1195
|
const onKeyDown = (e) => {
|
|
1339
1196
|
const elementTarget = e.target instanceof HTMLElement ? e.target : null;
|
|
1340
1197
|
const isTextInputTarget = elementTarget &&
|
|
1341
|
-
(elementTarget.nodeName ===
|
|
1342
|
-
(elementTarget.nodeName ===
|
|
1198
|
+
(elementTarget.nodeName === 'TEXTAREA' ||
|
|
1199
|
+
(elementTarget.nodeName === 'INPUT' && elementTarget.getAttribute('type') === 'text'));
|
|
1343
1200
|
switch (e.key) {
|
|
1344
1201
|
case Keys.HOME:
|
|
1345
1202
|
// Don't eat home/end events on inputs
|
|
@@ -1383,14 +1240,14 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1383
1240
|
e.stopPropagation();
|
|
1384
1241
|
};
|
|
1385
1242
|
const onAnimationEnd = () => {
|
|
1386
|
-
if (state ===
|
|
1243
|
+
if (state === 'closing') {
|
|
1387
1244
|
setOverflowData(undefined); // reset overflowData after closing
|
|
1388
1245
|
}
|
|
1389
1246
|
endTransition && safeCall(endTransition);
|
|
1390
1247
|
};
|
|
1391
1248
|
const handlePosition = React.useCallback((noOverflowCheck) => {
|
|
1392
1249
|
if (!containerRef?.current) {
|
|
1393
|
-
if (process.env.NODE_ENV !==
|
|
1250
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1394
1251
|
console.error('[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');
|
|
1395
1252
|
}
|
|
1396
1253
|
return;
|
|
@@ -1404,7 +1261,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1404
1261
|
const positionHelpers = getPositionHelpers(containerRef, menuRef, scrollNodes.menu, boundingBoxPadding);
|
|
1405
1262
|
const { menuRect } = positionHelpers;
|
|
1406
1263
|
let results = {
|
|
1407
|
-
computedDirection:
|
|
1264
|
+
computedDirection: 'bottom',
|
|
1408
1265
|
x: 0,
|
|
1409
1266
|
y: 0,
|
|
1410
1267
|
};
|
|
@@ -1427,7 +1284,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1427
1284
|
let { y } = results;
|
|
1428
1285
|
const { x, arrowX, arrowY, computedDirection } = results;
|
|
1429
1286
|
let menuHeight = menuRect.height;
|
|
1430
|
-
if (!noOverflowCheck && overflow !==
|
|
1287
|
+
if (!noOverflowCheck && overflow !== 'visible') {
|
|
1431
1288
|
const { getTopOverflow, getBottomOverflow } = positionHelpers;
|
|
1432
1289
|
let height, overflowAmt;
|
|
1433
1290
|
const prevHeight = latestMenuSize.current.height;
|
|
@@ -1508,21 +1365,21 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1508
1365
|
}
|
|
1509
1366
|
}
|
|
1510
1367
|
let scroll = viewScroll;
|
|
1511
|
-
if (scrollNodes.anchors.length && scroll ===
|
|
1512
|
-
scroll =
|
|
1513
|
-
if (scroll ===
|
|
1368
|
+
if (scrollNodes.anchors.length && scroll === 'initial')
|
|
1369
|
+
scroll = 'auto';
|
|
1370
|
+
if (scroll === 'initial')
|
|
1514
1371
|
return;
|
|
1515
1372
|
const handleScroll = () => {
|
|
1516
|
-
if (scroll ===
|
|
1373
|
+
if (scroll === 'auto') {
|
|
1517
1374
|
batchedUpdates(() => handlePosition(true));
|
|
1518
1375
|
}
|
|
1519
1376
|
else {
|
|
1520
1377
|
safeCall(onClose, { reason: CloseReason.SCROLL });
|
|
1521
1378
|
}
|
|
1522
1379
|
};
|
|
1523
|
-
const scrollObservers = scrollNodes.anchors.concat(viewScroll !==
|
|
1524
|
-
scrollObservers.forEach((o) => o.addEventListener(
|
|
1525
|
-
return () => scrollObservers.forEach((o) => o.removeEventListener(
|
|
1380
|
+
const scrollObservers = scrollNodes.anchors.concat(viewScroll !== 'initial' ? menuScroll : []);
|
|
1381
|
+
scrollObservers.forEach((o) => o.addEventListener('scroll', handleScroll));
|
|
1382
|
+
return () => scrollObservers.forEach((o) => o.removeEventListener('scroll', handleScroll));
|
|
1526
1383
|
}, [rootAnchorRef, scrollNodes, isOpen, onClose, viewScroll, handlePosition]);
|
|
1527
1384
|
const hasOverflow = !!overflowData && overflowData.overflowAmt != null && overflowData.overflowAmt > 0;
|
|
1528
1385
|
React.useEffect(() => {
|
|
@@ -1530,11 +1387,11 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1530
1387
|
return;
|
|
1531
1388
|
const handleScroll = () => batchedUpdates(handlePosition);
|
|
1532
1389
|
const parentScroll = parentScrollingRef.current;
|
|
1533
|
-
parentScroll.addEventListener(
|
|
1534
|
-
return () => parentScroll.removeEventListener(
|
|
1390
|
+
parentScroll.addEventListener('scroll', handleScroll);
|
|
1391
|
+
return () => parentScroll.removeEventListener('scroll', handleScroll);
|
|
1535
1392
|
}, [isOpen, hasOverflow, parentScrollingRef, handlePosition]);
|
|
1536
1393
|
React.useEffect(() => {
|
|
1537
|
-
if (typeof ResizeObserver !==
|
|
1394
|
+
if (typeof ResizeObserver !== 'function' || reposition === 'initial')
|
|
1538
1395
|
return;
|
|
1539
1396
|
const resizeObserver = new ResizeObserver(([entry]) => {
|
|
1540
1397
|
const { borderBoxSize, target } = entry;
|
|
@@ -1559,12 +1416,12 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1559
1416
|
});
|
|
1560
1417
|
});
|
|
1561
1418
|
const observeTarget = menuRef.current;
|
|
1562
|
-
resizeObserver.observe(observeTarget, { box:
|
|
1419
|
+
resizeObserver.observe(observeTarget, { box: 'border-box' });
|
|
1563
1420
|
return () => resizeObserver.unobserve(observeTarget);
|
|
1564
1421
|
}, [reposition]);
|
|
1565
1422
|
// Matt added window resize observer
|
|
1566
1423
|
React.useEffect(() => {
|
|
1567
|
-
if (typeof ResizeObserver !==
|
|
1424
|
+
if (typeof ResizeObserver !== 'function' || reposition === 'initial')
|
|
1568
1425
|
return;
|
|
1569
1426
|
const callback = lodashEs.debounce(() => {
|
|
1570
1427
|
const { width, height } = menuRef.current.ownerDocument.body.getBoundingClientRect();
|
|
@@ -1582,7 +1439,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1582
1439
|
}, 250);
|
|
1583
1440
|
const resizeObserver = new ResizeObserver(callback);
|
|
1584
1441
|
const observeTarget = menuRef.current.ownerDocument.body;
|
|
1585
|
-
resizeObserver.observe(observeTarget, { box:
|
|
1442
|
+
resizeObserver.observe(observeTarget, { box: 'border-box' });
|
|
1586
1443
|
return () => {
|
|
1587
1444
|
callback.cancel();
|
|
1588
1445
|
resizeObserver.unobserve(observeTarget);
|
|
@@ -1603,7 +1460,7 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1603
1460
|
else if (position === FocusPositions.LAST) {
|
|
1604
1461
|
dispatch(HoverActionTypes.LAST, undefined, 0);
|
|
1605
1462
|
}
|
|
1606
|
-
else if (typeof position ===
|
|
1463
|
+
else if (typeof position === 'number' && position >= -1) {
|
|
1607
1464
|
dispatch(HoverActionTypes.SET_INDEX, undefined, position);
|
|
1608
1465
|
}
|
|
1609
1466
|
};
|
|
@@ -1665,10 +1522,10 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1665
1522
|
if (minHeight.current < h)
|
|
1666
1523
|
minHeight.current = h;
|
|
1667
1524
|
}
|
|
1668
|
-
const dontShrinkOps = React.useMemo(() => expandedDirection ===
|
|
1525
|
+
const dontShrinkOps = React.useMemo(() => expandedDirection === 'top' && dontShrinkIfDirectionIsTop
|
|
1669
1526
|
? {
|
|
1670
|
-
overflowY: isSubmenuOpen ?
|
|
1671
|
-
minHeight: (isSubmenuOpen ? 0 : minHeight.current) +
|
|
1527
|
+
overflowY: isSubmenuOpen ? '' : 'auto',
|
|
1528
|
+
minHeight: (isSubmenuOpen ? 0 : minHeight.current) + 'px',
|
|
1672
1529
|
}
|
|
1673
1530
|
: undefined, [dontShrinkIfDirectionIsTop, expandedDirection, isSubmenuOpen]);
|
|
1674
1531
|
return (jsxRuntime.jsxs("ul", { role: "menu", "aria-label": ariaLabel, ...mergeProps({ onKeyDown, onAnimationEnd }, restProps), ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuRef), className: useBEM({ block: menuClass, modifiers, className: menuClassName }), style: {
|
|
@@ -1676,18 +1533,18 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1676
1533
|
...overflowStyle,
|
|
1677
1534
|
...dontShrinkOps,
|
|
1678
1535
|
margin: 0,
|
|
1679
|
-
display: state ===
|
|
1680
|
-
position:
|
|
1536
|
+
display: state === 'closed' ? 'none' : undefined,
|
|
1537
|
+
position: 'absolute',
|
|
1681
1538
|
left: menuPosition.x,
|
|
1682
1539
|
top: menuPosition.y,
|
|
1683
|
-
}, children: [jsxRuntime.jsx("div", { ref: focusRef, tabIndex: -1, style: { position:
|
|
1684
|
-
if (event.key ==
|
|
1540
|
+
}, children: [jsxRuntime.jsx("div", { ref: focusRef, tabIndex: -1, style: { position: 'absolute', left: 0, top: 0 }, onKeyDown: (event) => {
|
|
1541
|
+
if (event.key == 'Tab') {
|
|
1685
1542
|
event.preventDefault();
|
|
1686
1543
|
event.stopPropagation();
|
|
1687
1544
|
safeCall(onClose, {
|
|
1688
1545
|
key: event.key,
|
|
1689
1546
|
shiftKey: event.shiftKey,
|
|
1690
|
-
reason: event.key ===
|
|
1547
|
+
reason: event.key === 'Tab'
|
|
1691
1548
|
? event.shiftKey
|
|
1692
1549
|
? CloseReason.TAB_BACKWARD
|
|
1693
1550
|
: CloseReason.TAB_FORWARD
|
|
@@ -1696,13 +1553,13 @@ const MenuList = ({ ariaLabel, menuClassName, menuStyle, arrowClassName, arrowSt
|
|
|
1696
1553
|
}
|
|
1697
1554
|
} }), arrow && (jsxRuntime.jsx("div", { className: _arrowClass, style: {
|
|
1698
1555
|
...arrowStyle,
|
|
1699
|
-
position:
|
|
1556
|
+
position: 'absolute',
|
|
1700
1557
|
left: arrowPosition.x,
|
|
1701
1558
|
top: arrowPosition.y,
|
|
1702
1559
|
}, ref: arrowRef })), jsxRuntime.jsx(MenuListContext.Provider, { value: listContext, children: jsxRuntime.jsx(MenuListItemContext.Provider, { value: itemContext, children: jsxRuntime.jsx(HoverItemContext.Provider, { value: hoverItem, children: children }) }) })] }));
|
|
1703
1560
|
};
|
|
1704
1561
|
|
|
1705
|
-
const ControlledMenuFr = ({
|
|
1562
|
+
const ControlledMenuFr = ({ 'aria-label': ariaLabel, className, containerProps, initialMounted, unmountOnClose, transition, transitionTimeout, boundingBoxRef, boundingBoxPadding, reposition = 'auto', submenuOpenDelay = 300, submenuCloseDelay = 150, skipOpen, viewScroll = 'initial', portal, theming, onItemClick, onClose, saveButtonRef, ...restProps }, externalRef) => {
|
|
1706
1563
|
const containerRef = React.useRef();
|
|
1707
1564
|
const scrollNodesRef = React.useRef({});
|
|
1708
1565
|
const { anchorRef, state } = restProps;
|
|
@@ -1729,10 +1586,10 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1729
1586
|
reposition,
|
|
1730
1587
|
viewScroll,
|
|
1731
1588
|
]);
|
|
1732
|
-
const isWithinMenu = React.useCallback((target) => hasParentClass(
|
|
1589
|
+
const isWithinMenu = React.useCallback((target) => hasParentClass('szh-menu--state-open', target) ||
|
|
1733
1590
|
// This is temporary, it will be removed when the overlay click is fixed
|
|
1734
|
-
hasParentClass(
|
|
1735
|
-
hasParentClass(
|
|
1591
|
+
hasParentClass('LuiModalPrefab', target) ||
|
|
1592
|
+
hasParentClass('prefab-modal', target), []);
|
|
1736
1593
|
const handleScreenEventForSave = React.useCallback((ev) => {
|
|
1737
1594
|
if (!isWithinMenu(ev.target)) {
|
|
1738
1595
|
ev.preventDefault();
|
|
@@ -1742,7 +1599,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1742
1599
|
// This doesn't happen in React18
|
|
1743
1600
|
// To work around it, I invoke the save by clicking on a passed in invisible button ref
|
|
1744
1601
|
if (saveButtonRef?.current) {
|
|
1745
|
-
saveButtonRef.current.setAttribute(
|
|
1602
|
+
saveButtonRef.current.setAttribute('data-reason', CloseReason.BLUR);
|
|
1746
1603
|
saveButtonRef.current.click();
|
|
1747
1604
|
}
|
|
1748
1605
|
else
|
|
@@ -1772,7 +1629,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1772
1629
|
const activeElement = thisDocument.activeElement;
|
|
1773
1630
|
if (!anchorRef?.current || !activeElement)
|
|
1774
1631
|
return;
|
|
1775
|
-
if (ev.key !==
|
|
1632
|
+
if (ev.key !== 'Tab' && ev.key !== 'Enter')
|
|
1776
1633
|
return;
|
|
1777
1634
|
if (ev.repeat) {
|
|
1778
1635
|
ev.preventDefault();
|
|
@@ -1782,12 +1639,12 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1782
1639
|
const invokeSave = (reason) => {
|
|
1783
1640
|
if (!saveButtonRef?.current)
|
|
1784
1641
|
return;
|
|
1785
|
-
saveButtonRef.current?.setAttribute(
|
|
1642
|
+
saveButtonRef.current?.setAttribute('data-reason', reason);
|
|
1786
1643
|
saveButtonRef?.current?.click();
|
|
1787
1644
|
};
|
|
1788
1645
|
// data-allowtabtosave is used such that list filter inputs can use tab to save
|
|
1789
|
-
const allowTabToSave = activeElement.getAttribute(
|
|
1790
|
-
const inputElsIterator = thisDocument.querySelectorAll(
|
|
1646
|
+
const allowTabToSave = activeElement.getAttribute('data-allowtabtosave') == 'true';
|
|
1647
|
+
const inputElsIterator = thisDocument.querySelectorAll('.szh-menu--state-open input,textarea');
|
|
1791
1648
|
let inputEls = [];
|
|
1792
1649
|
inputElsIterator.forEach((el) => inputEls.push(el));
|
|
1793
1650
|
inputEls = inputEls.filter((el) => !el.disabled);
|
|
@@ -1795,9 +1652,9 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1795
1652
|
return;
|
|
1796
1653
|
const firstInputEl = inputEls[0];
|
|
1797
1654
|
const lastInputEl = inputEls[inputEls.length - 1];
|
|
1798
|
-
const isTextArea = activeElement.nodeName ===
|
|
1799
|
-
const suppressEnterAutoSave = activeElement.getAttribute(
|
|
1800
|
-
if (ev.key ===
|
|
1655
|
+
const isTextArea = activeElement.nodeName === 'TEXTAREA';
|
|
1656
|
+
const suppressEnterAutoSave = activeElement.getAttribute('data-disableenterautosave') == 'true' || isTextArea;
|
|
1657
|
+
if (ev.key === 'Tab') {
|
|
1801
1658
|
const tabDirection = ev.shiftKey ? CloseReason.TAB_BACKWARD : CloseReason.TAB_FORWARD;
|
|
1802
1659
|
if ((activeElement === lastInputEl && !ev.shiftKey) ||
|
|
1803
1660
|
(activeElement === firstInputEl && ev.shiftKey) ||
|
|
@@ -1812,13 +1669,13 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1812
1669
|
}
|
|
1813
1670
|
}
|
|
1814
1671
|
}
|
|
1815
|
-
const type = activeElement.getAttribute(
|
|
1816
|
-
const isTextInput = type ===
|
|
1672
|
+
const type = activeElement.getAttribute('type');
|
|
1673
|
+
const isTextInput = type === 'text' || type == null || type === 'textarea';
|
|
1817
1674
|
switch (activeElement.nodeName) {
|
|
1818
|
-
case
|
|
1675
|
+
case 'INPUT':
|
|
1819
1676
|
{
|
|
1820
1677
|
// If there's only one input element, we support tab and enter
|
|
1821
|
-
if (isTextInput && ev.key ===
|
|
1678
|
+
if (isTextInput && ev.key === 'Enter' && !suppressEnterAutoSave) {
|
|
1822
1679
|
ev.preventDefault();
|
|
1823
1680
|
ev.stopPropagation();
|
|
1824
1681
|
if (isDown) {
|
|
@@ -1837,19 +1694,19 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1837
1694
|
React.useEffect(() => {
|
|
1838
1695
|
if (isMenuOpen(state)) {
|
|
1839
1696
|
const thisDocument = anchorRef?.current ? anchorRef?.current.ownerDocument : document;
|
|
1840
|
-
thisDocument.addEventListener(
|
|
1841
|
-
thisDocument.addEventListener(
|
|
1842
|
-
thisDocument.addEventListener(
|
|
1843
|
-
thisDocument.addEventListener(
|
|
1844
|
-
thisDocument.addEventListener(
|
|
1845
|
-
thisDocument.addEventListener(
|
|
1697
|
+
thisDocument.addEventListener('keydown', handleKeydownTabAndEnter, true);
|
|
1698
|
+
thisDocument.addEventListener('keyup', handleKeyupTabAndEnter, true);
|
|
1699
|
+
thisDocument.addEventListener('mousedown', handleScreenEventForSave, true);
|
|
1700
|
+
thisDocument.addEventListener('mouseup', handleScreenEventForCancel, true);
|
|
1701
|
+
thisDocument.addEventListener('click', handleScreenEventForCancel, true);
|
|
1702
|
+
thisDocument.addEventListener('dblclick', handleScreenEventForCancel, true);
|
|
1846
1703
|
return () => {
|
|
1847
|
-
thisDocument.removeEventListener(
|
|
1848
|
-
thisDocument.removeEventListener(
|
|
1849
|
-
thisDocument.removeEventListener(
|
|
1850
|
-
thisDocument.removeEventListener(
|
|
1851
|
-
thisDocument.removeEventListener(
|
|
1852
|
-
thisDocument.removeEventListener(
|
|
1704
|
+
thisDocument.removeEventListener('keydown', handleKeydownTabAndEnter, true);
|
|
1705
|
+
thisDocument.removeEventListener('keyup', handleKeyupTabAndEnter, true);
|
|
1706
|
+
thisDocument.removeEventListener('mousedown', handleScreenEventForSave, true);
|
|
1707
|
+
thisDocument.removeEventListener('mouseup', handleScreenEventForCancel, true);
|
|
1708
|
+
thisDocument.removeEventListener('click', handleScreenEventForCancel, true);
|
|
1709
|
+
thisDocument.removeEventListener('dblclick', handleScreenEventForCancel, true);
|
|
1853
1710
|
};
|
|
1854
1711
|
}
|
|
1855
1712
|
return () => { };
|
|
@@ -1881,7 +1738,7 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1881
1738
|
value: event.value,
|
|
1882
1739
|
key: event.key,
|
|
1883
1740
|
shiftKey: event.shiftKey,
|
|
1884
|
-
reason: event.key ===
|
|
1741
|
+
reason: event.key === 'Tab'
|
|
1885
1742
|
? event.shiftKey
|
|
1886
1743
|
? CloseReason.TAB_BACKWARD
|
|
1887
1744
|
: CloseReason.TAB_FORWARD
|
|
@@ -1919,15 +1776,15 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1919
1776
|
}
|
|
1920
1777
|
}
|
|
1921
1778
|
};
|
|
1922
|
-
const itemTransition = getTransition(transition,
|
|
1779
|
+
const itemTransition = getTransition(transition, 'item');
|
|
1923
1780
|
const modifiers = React.useMemo(() => ({ theme: theming, itemTransition }), [theming, itemTransition]);
|
|
1924
1781
|
const menuList = (jsxRuntime.jsx("div", { ...mergeProps({ onKeyUp, onBlur }, containerProps), className: useBEM({
|
|
1925
1782
|
block: menuContainerClass,
|
|
1926
1783
|
modifiers,
|
|
1927
1784
|
className,
|
|
1928
|
-
}), style: { ...containerProps?.style, position:
|
|
1785
|
+
}), style: { ...containerProps?.style, position: 'relative' }, ref: containerRef, children: state && (jsxRuntime.jsx(SettingsContext.Provider, { value: settings, children: jsxRuntime.jsx(ItemSettingsContext.Provider, { value: itemSettings, children: jsxRuntime.jsx(EventHandlersContext.Provider, { value: eventHandlers, children: jsxRuntime.jsx(MenuList, { ...restProps, ariaLabel: ariaLabel || 'Menu', externalRef: externalRef, containerRef: containerRef, onClose: onClose }) }) }) })) }));
|
|
1929
1786
|
if (portal === true && anchorRef?.current != null) {
|
|
1930
|
-
if (hasParentClass(
|
|
1787
|
+
if (hasParentClass('react-menu-inline-test', anchorRef.current)) {
|
|
1931
1788
|
portal = false;
|
|
1932
1789
|
}
|
|
1933
1790
|
else {
|
|
@@ -1935,8 +1792,8 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1935
1792
|
}
|
|
1936
1793
|
}
|
|
1937
1794
|
if (portal) {
|
|
1938
|
-
if (typeof portal ===
|
|
1939
|
-
if (portal && typeof document !==
|
|
1795
|
+
if (typeof portal === 'boolean') {
|
|
1796
|
+
if (portal && typeof document !== 'undefined') {
|
|
1940
1797
|
return reactDom.createPortal(menuList, document.body);
|
|
1941
1798
|
}
|
|
1942
1799
|
}
|
|
@@ -1948,7 +1805,31 @@ const ControlledMenuFr = ({ "aria-label": ariaLabel, className, containerProps,
|
|
|
1948
1805
|
};
|
|
1949
1806
|
const ControlledMenu = React.forwardRef(ControlledMenuFr);
|
|
1950
1807
|
|
|
1951
|
-
|
|
1808
|
+
const FocusableItemFr = ({ className, disabled, children, isHovering, menuItemRef, externalRef, ...restProps }) => {
|
|
1809
|
+
const isDisabled = !!disabled;
|
|
1810
|
+
const ref = React.useRef(null);
|
|
1811
|
+
const { setHover, onPointerLeave, ...restStateProps } = useItemState(menuItemRef, ref, isHovering, isDisabled);
|
|
1812
|
+
const { handleClose } = React.useContext(EventHandlersContext);
|
|
1813
|
+
const modifiers = React.useMemo(() => ({
|
|
1814
|
+
disabled: isDisabled,
|
|
1815
|
+
hover: isHovering,
|
|
1816
|
+
focusable: true,
|
|
1817
|
+
}), [isDisabled, isHovering]);
|
|
1818
|
+
const renderChildren = React.useMemo(() => safeCall(children, {
|
|
1819
|
+
...modifiers,
|
|
1820
|
+
ref,
|
|
1821
|
+
closeMenu: handleClose,
|
|
1822
|
+
}), [children, modifiers, handleClose]);
|
|
1823
|
+
const mergedProps = mergeProps({
|
|
1824
|
+
...restStateProps,
|
|
1825
|
+
onPointerLeave: (e) => onPointerLeave(e, true),
|
|
1826
|
+
onFocus: setHover,
|
|
1827
|
+
}, restProps);
|
|
1828
|
+
return (jsxRuntime.jsx("li", { role: "menuitem", ...mergedProps, ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuItemRef), className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }), children: renderChildren }));
|
|
1829
|
+
};
|
|
1830
|
+
const FocusableItem = withHovering('FocusableItem', FocusableItemFr);
|
|
1831
|
+
|
|
1832
|
+
function MenuFr({ 'aria-label': ariaLabel, menuButton, instanceRef, onMenuChange, ...restProps }, externalRef) {
|
|
1952
1833
|
const [stateProps, toggleMenu, openMenu] = useMenuStateAndFocus(restProps);
|
|
1953
1834
|
const isOpen = isMenuOpen(stateProps.state);
|
|
1954
1835
|
const skipOpen = React.useRef(false);
|
|
@@ -1980,13 +1861,13 @@ function MenuFr({ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange
|
|
|
1980
1861
|
// Too many mixed types here to figure out what to pick for button. Bad code.
|
|
1981
1862
|
const button = safeCall(menuButton, { open: isOpen });
|
|
1982
1863
|
if (!button || !button.type)
|
|
1983
|
-
throw new Error(
|
|
1864
|
+
throw new Error('Menu requires a menuButton prop.');
|
|
1984
1865
|
const buttonProps = {
|
|
1985
1866
|
ref: useCombinedRef(button.ref, buttonRef),
|
|
1986
1867
|
...mergeProps({ onClick, onKeyDown }, button.props),
|
|
1987
1868
|
isOpen: false,
|
|
1988
1869
|
};
|
|
1989
|
-
if (getName(button.type) ===
|
|
1870
|
+
if (getName(button.type) === 'MenuButton') {
|
|
1990
1871
|
buttonProps.isOpen = isOpen;
|
|
1991
1872
|
}
|
|
1992
1873
|
const renderButton = React.cloneElement(button, buttonProps);
|
|
@@ -1995,17 +1876,165 @@ function MenuFr({ "aria-label": ariaLabel, menuButton, instanceRef, onMenuChange
|
|
|
1995
1876
|
openMenu,
|
|
1996
1877
|
closeMenu: () => toggleMenu(false),
|
|
1997
1878
|
}));
|
|
1998
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [renderButton, jsxRuntime.jsx(ControlledMenu, { ...restProps, ...stateProps, "aria-label": ariaLabel || (typeof button.props.children ===
|
|
1879
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [renderButton, jsxRuntime.jsx(ControlledMenu, { ...restProps, ...stateProps, "aria-label": ariaLabel || (typeof button.props.children === 'string' ? button.props.children : 'Menu'), anchorRef: buttonRef, ref: externalRef, onClose: handleClose, skipOpen: skipOpen })] }));
|
|
1999
1880
|
}
|
|
2000
1881
|
const Menu = React.forwardRef(MenuFr);
|
|
2001
1882
|
|
|
2002
|
-
const
|
|
1883
|
+
const MenuButton = React.forwardRef(function MenuButton({ className, isOpen, disabled, children, ...restProps }, ref) {
|
|
1884
|
+
const modifiers = React.useMemo(() => ({ open: isOpen }), [isOpen]);
|
|
1885
|
+
return (jsxRuntime.jsx("button", { "aria-haspopup": true, "aria-expanded": isOpen, "aria-disabled": disabled || undefined, type: "button", disabled: disabled, ...restProps, ref: ref, className: useBEM({ block: menuButtonClass, modifiers, className }), children: children }));
|
|
1886
|
+
});
|
|
1887
|
+
|
|
1888
|
+
const MenuDividerFr = ({ className, ...restProps }, externalRef) => {
|
|
1889
|
+
return (jsxRuntime.jsx("li", { role: "separator", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuDividerClass, className }) }));
|
|
1890
|
+
};
|
|
1891
|
+
const MenuDivider = React.memo(React.forwardRef(MenuDividerFr));
|
|
1892
|
+
|
|
1893
|
+
const MenuGroupFr = ({ className, style, takeOverflow, ...restProps }, externalRef) => {
|
|
1894
|
+
const ref = React.useRef(null);
|
|
1895
|
+
const [overflowStyle, setOverflowStyle] = React.useState();
|
|
1896
|
+
const { overflow, overflowAmt } = React.useContext(MenuListContext);
|
|
1897
|
+
useIsomorphicLayoutEffect(() => {
|
|
1898
|
+
let maxHeight;
|
|
1899
|
+
if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
|
|
1900
|
+
maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
|
|
1901
|
+
if (maxHeight < 0)
|
|
1902
|
+
maxHeight = 0;
|
|
1903
|
+
}
|
|
1904
|
+
setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
|
|
1905
|
+
}, [takeOverflow, overflow, overflowAmt]);
|
|
1906
|
+
useIsomorphicLayoutEffect(() => {
|
|
1907
|
+
if (overflowStyle && ref.current)
|
|
1908
|
+
ref.current.scrollTop = 0;
|
|
1909
|
+
}, [overflowStyle]);
|
|
1910
|
+
return (jsxRuntime.jsx("div", { ...restProps, ref: useCombinedRef(externalRef, ref), className: useBEM({ block: menuClass, element: menuGroupClass, className }), style: { ...style, ...overflowStyle } }));
|
|
1911
|
+
};
|
|
1912
|
+
const MenuGroup = React.forwardRef(MenuGroupFr);
|
|
1913
|
+
|
|
1914
|
+
const MenuHeaderFr = ({ className, ...restProps }, externalRef) => {
|
|
1915
|
+
return (jsxRuntime.jsx("li", { role: "presentation", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuHeaderClass, className }) }));
|
|
1916
|
+
};
|
|
1917
|
+
const MenuHeader = React.memo(React.forwardRef(MenuHeaderFr));
|
|
1918
|
+
|
|
1919
|
+
const RadioGroupContext = React.createContext({});
|
|
1920
|
+
|
|
1921
|
+
const MenuItemFr = ({ className, value, href, type, checked, disabled, children, onClick, isHovering, menuItemRef, externalRef, ...restProps }) => {
|
|
1922
|
+
const isDisabled = !!disabled;
|
|
1923
|
+
const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
|
|
1924
|
+
const eventHandlers = React.useContext(EventHandlersContext);
|
|
1925
|
+
const radioGroup = React.useContext(RadioGroupContext);
|
|
1926
|
+
const isRadio = type === 'radio';
|
|
1927
|
+
const isCheckBox = type === 'checkbox';
|
|
1928
|
+
const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
|
|
1929
|
+
const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
|
|
1930
|
+
// handle click seems to be a combination of multiple event types, bad code.
|
|
1931
|
+
const handleClick = (e) => {
|
|
1932
|
+
if (isDisabled) {
|
|
1933
|
+
if (e.syntheticEvent) {
|
|
1934
|
+
e.syntheticEvent.stopPropagation();
|
|
1935
|
+
e.syntheticEvent.preventDefault();
|
|
1936
|
+
}
|
|
1937
|
+
else {
|
|
1938
|
+
e.stopPropagation();
|
|
1939
|
+
e.preventDefault();
|
|
1940
|
+
}
|
|
1941
|
+
return;
|
|
1942
|
+
}
|
|
1943
|
+
const event = {
|
|
1944
|
+
value,
|
|
1945
|
+
syntheticEvent: e,
|
|
1946
|
+
};
|
|
1947
|
+
if (e.key !== undefined) {
|
|
1948
|
+
const ke = e;
|
|
1949
|
+
event.key = ke.key;
|
|
1950
|
+
event.shiftKey = ke.shiftKey;
|
|
1951
|
+
}
|
|
1952
|
+
if (isCheckBox)
|
|
1953
|
+
event.checked = !isChecked;
|
|
1954
|
+
if (isRadio)
|
|
1955
|
+
event.name = radioGroup.name;
|
|
1956
|
+
safeCall(onClick, event);
|
|
1957
|
+
if (isRadio)
|
|
1958
|
+
safeCall(radioGroup.onRadioChange, event);
|
|
1959
|
+
eventHandlers.handleClick(event, isCheckBox || isRadio);
|
|
1960
|
+
};
|
|
1961
|
+
const handleKeyDown = (e) => {
|
|
1962
|
+
// if tab is allowed the handleKeyUp event can't process the tab
|
|
1963
|
+
if (e.key === 'Tab') {
|
|
1964
|
+
e.preventDefault();
|
|
1965
|
+
e.stopPropagation();
|
|
1966
|
+
}
|
|
1967
|
+
};
|
|
1968
|
+
/**
|
|
1969
|
+
* Keyboard events are triggered on up, otherwise subcomponents get spaces and enters typed in them
|
|
1970
|
+
*/
|
|
1971
|
+
const handleKeyUp = (e) => {
|
|
1972
|
+
if (!isHovering)
|
|
1973
|
+
return;
|
|
1974
|
+
switch (e.key) {
|
|
1975
|
+
case Keys.ENTER:
|
|
1976
|
+
case Keys.TAB:
|
|
1977
|
+
case Keys.SPACE:
|
|
1978
|
+
e.preventDefault();
|
|
1979
|
+
e.stopPropagation();
|
|
1980
|
+
if (isAnchor) {
|
|
1981
|
+
menuItemRef?.current && menuItemRef.current.click();
|
|
1982
|
+
}
|
|
1983
|
+
else {
|
|
1984
|
+
handleClick(e);
|
|
1985
|
+
}
|
|
1986
|
+
break;
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
const modifiers = React.useMemo(() => ({
|
|
1990
|
+
type,
|
|
1991
|
+
disabled: isDisabled,
|
|
1992
|
+
hover: isHovering,
|
|
1993
|
+
checked: isChecked,
|
|
1994
|
+
anchor: isAnchor,
|
|
1995
|
+
}), [type, isDisabled, isHovering, isChecked, isAnchor]);
|
|
1996
|
+
const mergedProps = mergeProps({
|
|
1997
|
+
...restStateProps,
|
|
1998
|
+
onPointerDown: setHover,
|
|
1999
|
+
onKeyDown: handleKeyDown,
|
|
2000
|
+
onKeyUp: handleKeyUp,
|
|
2001
|
+
onClick: handleClick,
|
|
2002
|
+
}, restProps);
|
|
2003
|
+
// Order of props overriding (same in all components):
|
|
2004
|
+
// 1. Preset props adhering to WAI-ARIA Authoring Practices.
|
|
2005
|
+
// 2. Merged outer and local props
|
|
2006
|
+
// 3. ref, className
|
|
2007
|
+
const menuItemProps = {
|
|
2008
|
+
role: isRadio ? 'menuitemradio' : isCheckBox ? 'menuitemcheckbox' : 'menuitem',
|
|
2009
|
+
'aria-checked': isRadio || isCheckBox ? isChecked : undefined,
|
|
2010
|
+
...mergedProps,
|
|
2011
|
+
...commonProps(isDisabled, isHovering),
|
|
2012
|
+
ref: useCombinedRef(externalRef, menuItemRef),
|
|
2013
|
+
className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
|
|
2014
|
+
children: React.useMemo(() => safeCall(children, modifiers), [children, modifiers]),
|
|
2015
|
+
};
|
|
2016
|
+
if (isAnchor) {
|
|
2017
|
+
return (jsxRuntime.jsx("li", { role: "presentation", children: jsxRuntime.jsx("a", { href: href, ...menuItemProps }) }));
|
|
2018
|
+
}
|
|
2019
|
+
else {
|
|
2020
|
+
return jsxRuntime.jsx("li", { ...menuItemProps });
|
|
2021
|
+
}
|
|
2022
|
+
};
|
|
2023
|
+
const MenuItem = withHovering('MenuItem', MenuItemFr);
|
|
2024
|
+
|
|
2025
|
+
const MenuRadioGroupFr = ({ 'aria-label': ariaLabel, className, name, value, onRadioChange, ...restProps }, externalRef) => {
|
|
2026
|
+
const contextValue = React.useMemo(() => ({ name, value, onRadioChange }), [name, value, onRadioChange]);
|
|
2027
|
+
return (jsxRuntime.jsx(RadioGroupContext.Provider, { value: contextValue, children: jsxRuntime.jsx("li", { role: "presentation", children: jsxRuntime.jsx("ul", { role: "group", "aria-label": ariaLabel || name || 'Radio group', ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: radioGroupClass, className }) }) }) }));
|
|
2028
|
+
};
|
|
2029
|
+
const MenuRadioGroup = React.forwardRef(MenuRadioGroupFr);
|
|
2030
|
+
|
|
2031
|
+
const SubMenuFr = ({ 'aria-label': ariaLabel, className, disabled, direction, label, openTrigger, onMenuChange, isHovering, instanceRef, menuItemRef, itemProps = {}, ...restProps }) => {
|
|
2003
2032
|
const settings = React.useContext(SettingsContext);
|
|
2004
2033
|
const { rootMenuRef } = settings;
|
|
2005
2034
|
const { submenuOpenDelay, submenuCloseDelay } = React.useContext(ItemSettingsContext);
|
|
2006
2035
|
const { parentMenuRef, parentDir, overflow: parentOverflow } = React.useContext(MenuListContext);
|
|
2007
2036
|
const { isParentOpen, isSubmenuOpen, setOpenSubmenuCount, dispatch, updateItems } = React.useContext(MenuListItemContext);
|
|
2008
|
-
const isPortal = parentOverflow !==
|
|
2037
|
+
const isPortal = parentOverflow !== 'visible';
|
|
2009
2038
|
const [stateProps, toggleMenu, _openMenu] = useMenuStateAndFocus(settings);
|
|
2010
2039
|
const { state } = stateProps;
|
|
2011
2040
|
const isDisabled = !!disabled;
|
|
@@ -2073,7 +2102,7 @@ const SubMenuFr = ({ "aria-label": ariaLabel, className, disabled, direction, la
|
|
|
2073
2102
|
case Keys.ENTER:
|
|
2074
2103
|
case Keys.SPACE:
|
|
2075
2104
|
case Keys.RIGHT:
|
|
2076
|
-
openTrigger !==
|
|
2105
|
+
openTrigger !== 'none' && openMenu(FocusPositions.FIRST);
|
|
2077
2106
|
break;
|
|
2078
2107
|
}
|
|
2079
2108
|
};
|
|
@@ -2115,188 +2144,21 @@ const SubMenuFr = ({ "aria-label": ariaLabel, className, disabled, direction, la
|
|
|
2115
2144
|
onPointerMove: handlePointerMove,
|
|
2116
2145
|
onPointerLeave: handlePointerLeave,
|
|
2117
2146
|
onKeyDown: handleItemKeyDown,
|
|
2118
|
-
onClick: () => openTrigger !==
|
|
2147
|
+
onClick: () => openTrigger !== 'none' && openMenu(),
|
|
2119
2148
|
}, restItemProps);
|
|
2120
2149
|
const getMenuList = () => {
|
|
2121
|
-
const menuList = (jsxRuntime.jsx(MenuList, { ...restProps, ...stateProps, ariaLabel: ariaLabel || (typeof label ===
|
|
2150
|
+
const menuList = (jsxRuntime.jsx(MenuList, { ...restProps, ...stateProps, ariaLabel: ariaLabel || (typeof label === 'string' ? label : 'Submenu'), anchorRef: menuItemRef, containerRef: isPortal ? rootMenuRef : containerRef, direction: direction || (parentDir === 'right' || parentDir === 'left' ? parentDir : 'right'), parentScrollingRef: isPortal && parentMenuRef, isDisabled: isDisabled }));
|
|
2122
2151
|
const container = rootMenuRef?.current;
|
|
2123
2152
|
return isPortal && container ? reactDom.createPortal(menuList, container) : menuList;
|
|
2124
2153
|
};
|
|
2125
|
-
return (jsxRuntime.jsxs("li", { className: useBEM({ block: menuClass, element: subMenuClass, className }), style: { position:
|
|
2154
|
+
return (jsxRuntime.jsxs("li", { className: useBEM({ block: menuClass, element: subMenuClass, className }), style: { position: 'relative' }, role: "presentation", ref: containerRef, onKeyDown: handleKeyDown, children: [jsxRuntime.jsx("div", { role: "menuitem", "aria-haspopup": true, "aria-expanded": isOpen, ...mergedItemProps, ...commonProps(isDisabled, isHovering), ref: useCombinedRef(externalItemRef, menuItemRef), className: useBEM({
|
|
2126
2155
|
block: menuClass,
|
|
2127
2156
|
element: menuItemClass,
|
|
2128
2157
|
modifiers,
|
|
2129
2158
|
className: itemClassName,
|
|
2130
2159
|
}), children: React.useMemo(() => safeCall(label, modifiers), [label, modifiers]) }), state && getMenuList()] }));
|
|
2131
2160
|
};
|
|
2132
|
-
const SubMenu = withHovering(
|
|
2133
|
-
|
|
2134
|
-
const RadioGroupContext = React.createContext({});
|
|
2135
|
-
|
|
2136
|
-
const MenuItemFr = ({ className, value, href, type, checked, disabled, children, onClick, isHovering, menuItemRef, externalRef, ...restProps }) => {
|
|
2137
|
-
const isDisabled = !!disabled;
|
|
2138
|
-
const { setHover, ...restStateProps } = useItemState(menuItemRef, menuItemRef, isHovering, isDisabled);
|
|
2139
|
-
const eventHandlers = React.useContext(EventHandlersContext);
|
|
2140
|
-
const radioGroup = React.useContext(RadioGroupContext);
|
|
2141
|
-
const isRadio = type === "radio";
|
|
2142
|
-
const isCheckBox = type === "checkbox";
|
|
2143
|
-
const isAnchor = !!href && !isDisabled && !isRadio && !isCheckBox;
|
|
2144
|
-
const isChecked = isRadio ? radioGroup.value === value : isCheckBox ? !!checked : false;
|
|
2145
|
-
// handle click seems to be a combination of multiple event types, bad code.
|
|
2146
|
-
const handleClick = (e) => {
|
|
2147
|
-
if (isDisabled) {
|
|
2148
|
-
if (e.syntheticEvent) {
|
|
2149
|
-
e.syntheticEvent.stopPropagation();
|
|
2150
|
-
e.syntheticEvent.preventDefault();
|
|
2151
|
-
}
|
|
2152
|
-
else {
|
|
2153
|
-
e.stopPropagation();
|
|
2154
|
-
e.preventDefault();
|
|
2155
|
-
}
|
|
2156
|
-
return;
|
|
2157
|
-
}
|
|
2158
|
-
const event = {
|
|
2159
|
-
value,
|
|
2160
|
-
syntheticEvent: e,
|
|
2161
|
-
};
|
|
2162
|
-
if (e.key !== undefined) {
|
|
2163
|
-
const ke = e;
|
|
2164
|
-
event.key = ke.key;
|
|
2165
|
-
event.shiftKey = ke.shiftKey;
|
|
2166
|
-
}
|
|
2167
|
-
if (isCheckBox)
|
|
2168
|
-
event.checked = !isChecked;
|
|
2169
|
-
if (isRadio)
|
|
2170
|
-
event.name = radioGroup.name;
|
|
2171
|
-
safeCall(onClick, event);
|
|
2172
|
-
if (isRadio)
|
|
2173
|
-
safeCall(radioGroup.onRadioChange, event);
|
|
2174
|
-
eventHandlers.handleClick(event, isCheckBox || isRadio);
|
|
2175
|
-
};
|
|
2176
|
-
const handleKeyDown = (e) => {
|
|
2177
|
-
// if tab is allowed the handleKeyUp event can't process the tab
|
|
2178
|
-
if (e.key === "Tab") {
|
|
2179
|
-
e.preventDefault();
|
|
2180
|
-
e.stopPropagation();
|
|
2181
|
-
}
|
|
2182
|
-
};
|
|
2183
|
-
/**
|
|
2184
|
-
* Keyboard events are triggered on up, otherwise subcomponents get spaces and enters typed in them
|
|
2185
|
-
*/
|
|
2186
|
-
const handleKeyUp = (e) => {
|
|
2187
|
-
if (!isHovering)
|
|
2188
|
-
return;
|
|
2189
|
-
switch (e.key) {
|
|
2190
|
-
case Keys.ENTER:
|
|
2191
|
-
case Keys.TAB:
|
|
2192
|
-
case Keys.SPACE:
|
|
2193
|
-
e.preventDefault();
|
|
2194
|
-
e.stopPropagation();
|
|
2195
|
-
if (isAnchor) {
|
|
2196
|
-
menuItemRef?.current && menuItemRef.current.click();
|
|
2197
|
-
}
|
|
2198
|
-
else {
|
|
2199
|
-
handleClick(e);
|
|
2200
|
-
}
|
|
2201
|
-
break;
|
|
2202
|
-
}
|
|
2203
|
-
};
|
|
2204
|
-
const modifiers = React.useMemo(() => ({
|
|
2205
|
-
type,
|
|
2206
|
-
disabled: isDisabled,
|
|
2207
|
-
hover: isHovering,
|
|
2208
|
-
checked: isChecked,
|
|
2209
|
-
anchor: isAnchor,
|
|
2210
|
-
}), [type, isDisabled, isHovering, isChecked, isAnchor]);
|
|
2211
|
-
const mergedProps = mergeProps({
|
|
2212
|
-
...restStateProps,
|
|
2213
|
-
onPointerDown: setHover,
|
|
2214
|
-
onKeyDown: handleKeyDown,
|
|
2215
|
-
onKeyUp: handleKeyUp,
|
|
2216
|
-
onClick: handleClick,
|
|
2217
|
-
}, restProps);
|
|
2218
|
-
// Order of props overriding (same in all components):
|
|
2219
|
-
// 1. Preset props adhering to WAI-ARIA Authoring Practices.
|
|
2220
|
-
// 2. Merged outer and local props
|
|
2221
|
-
// 3. ref, className
|
|
2222
|
-
const menuItemProps = {
|
|
2223
|
-
role: isRadio ? "menuitemradio" : isCheckBox ? "menuitemcheckbox" : "menuitem",
|
|
2224
|
-
"aria-checked": isRadio || isCheckBox ? isChecked : undefined,
|
|
2225
|
-
...mergedProps,
|
|
2226
|
-
...commonProps(isDisabled, isHovering),
|
|
2227
|
-
ref: useCombinedRef(externalRef, menuItemRef),
|
|
2228
|
-
className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }),
|
|
2229
|
-
children: React.useMemo(() => safeCall(children, modifiers), [children, modifiers]),
|
|
2230
|
-
};
|
|
2231
|
-
if (isAnchor) {
|
|
2232
|
-
return (jsxRuntime.jsx("li", { role: "presentation", children: jsxRuntime.jsx("a", { href: href, ...menuItemProps }) }));
|
|
2233
|
-
}
|
|
2234
|
-
else {
|
|
2235
|
-
return jsxRuntime.jsx("li", { ...menuItemProps });
|
|
2236
|
-
}
|
|
2237
|
-
};
|
|
2238
|
-
const MenuItem = withHovering("MenuItem", MenuItemFr);
|
|
2239
|
-
|
|
2240
|
-
const FocusableItemFr = ({ className, disabled, children, isHovering, menuItemRef, externalRef, ...restProps }) => {
|
|
2241
|
-
const isDisabled = !!disabled;
|
|
2242
|
-
const ref = React.useRef(null);
|
|
2243
|
-
const { setHover, onPointerLeave, ...restStateProps } = useItemState(menuItemRef, ref, isHovering, isDisabled);
|
|
2244
|
-
const { handleClose } = React.useContext(EventHandlersContext);
|
|
2245
|
-
const modifiers = React.useMemo(() => ({
|
|
2246
|
-
disabled: isDisabled,
|
|
2247
|
-
hover: isHovering,
|
|
2248
|
-
focusable: true,
|
|
2249
|
-
}), [isDisabled, isHovering]);
|
|
2250
|
-
const renderChildren = React.useMemo(() => safeCall(children, {
|
|
2251
|
-
...modifiers,
|
|
2252
|
-
ref,
|
|
2253
|
-
closeMenu: handleClose,
|
|
2254
|
-
}), [children, modifiers, handleClose]);
|
|
2255
|
-
const mergedProps = mergeProps({
|
|
2256
|
-
...restStateProps,
|
|
2257
|
-
onPointerLeave: (e) => onPointerLeave(e, true),
|
|
2258
|
-
onFocus: setHover,
|
|
2259
|
-
}, restProps);
|
|
2260
|
-
return (jsxRuntime.jsx("li", { role: "menuitem", ...mergedProps, ...commonProps(isDisabled), ref: useCombinedRef(externalRef, menuItemRef), className: useBEM({ block: menuClass, element: menuItemClass, modifiers, className }), children: renderChildren }));
|
|
2261
|
-
};
|
|
2262
|
-
const FocusableItem = withHovering("FocusableItem", FocusableItemFr);
|
|
2263
|
-
|
|
2264
|
-
const MenuDividerFr = ({ className, ...restProps }, externalRef) => {
|
|
2265
|
-
return (jsxRuntime.jsx("li", { role: "separator", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuDividerClass, className }) }));
|
|
2266
|
-
};
|
|
2267
|
-
const MenuDivider = React.memo(React.forwardRef(MenuDividerFr));
|
|
2268
|
-
|
|
2269
|
-
const MenuHeaderFr = ({ className, ...restProps }, externalRef) => {
|
|
2270
|
-
return (jsxRuntime.jsx("li", { role: "presentation", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: menuHeaderClass, className }) }));
|
|
2271
|
-
};
|
|
2272
|
-
const MenuHeader = React.memo(React.forwardRef(MenuHeaderFr));
|
|
2273
|
-
|
|
2274
|
-
const MenuGroupFr = ({ className, style, takeOverflow, ...restProps }, externalRef) => {
|
|
2275
|
-
const ref = React.useRef(null);
|
|
2276
|
-
const [overflowStyle, setOverflowStyle] = React.useState();
|
|
2277
|
-
const { overflow, overflowAmt } = React.useContext(MenuListContext);
|
|
2278
|
-
useIsomorphicLayoutEffect(() => {
|
|
2279
|
-
let maxHeight;
|
|
2280
|
-
if (takeOverflow && overflowAmt != null && overflowAmt >= 0 && ref.current) {
|
|
2281
|
-
maxHeight = ref.current.getBoundingClientRect().height - overflowAmt;
|
|
2282
|
-
if (maxHeight < 0)
|
|
2283
|
-
maxHeight = 0;
|
|
2284
|
-
}
|
|
2285
|
-
setOverflowStyle(maxHeight != null && maxHeight >= 0 ? { maxHeight, overflow } : undefined);
|
|
2286
|
-
}, [takeOverflow, overflow, overflowAmt]);
|
|
2287
|
-
useIsomorphicLayoutEffect(() => {
|
|
2288
|
-
if (overflowStyle && ref.current)
|
|
2289
|
-
ref.current.scrollTop = 0;
|
|
2290
|
-
}, [overflowStyle]);
|
|
2291
|
-
return (jsxRuntime.jsx("div", { ...restProps, ref: useCombinedRef(externalRef, ref), className: useBEM({ block: menuClass, element: menuGroupClass, className }), style: { ...style, ...overflowStyle } }));
|
|
2292
|
-
};
|
|
2293
|
-
const MenuGroup = React.forwardRef(MenuGroupFr);
|
|
2294
|
-
|
|
2295
|
-
const MenuRadioGroupFr = ({ "aria-label": ariaLabel, className, name, value, onRadioChange, ...restProps }, externalRef) => {
|
|
2296
|
-
const contextValue = React.useMemo(() => ({ name, value, onRadioChange }), [name, value, onRadioChange]);
|
|
2297
|
-
return (jsxRuntime.jsx(RadioGroupContext.Provider, { value: contextValue, children: jsxRuntime.jsx("li", { role: "presentation", children: jsxRuntime.jsx("ul", { role: "group", "aria-label": ariaLabel || name || "Radio group", ...restProps, ref: externalRef, className: useBEM({ block: menuClass, element: radioGroupClass, className }) }) }) }));
|
|
2298
|
-
};
|
|
2299
|
-
const MenuRadioGroup = React.forwardRef(MenuRadioGroupFr);
|
|
2161
|
+
const SubMenu = withHovering('SubMenu', SubMenuFr);
|
|
2300
2162
|
|
|
2301
2163
|
const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, }) => {
|
|
2302
2164
|
const { redrawRows, prePopupOps, postPopupOps, getSelectedRows } = React.useContext(GridContext);
|
|
@@ -2331,46 +2193,191 @@ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, })
|
|
|
2331
2193
|
return {
|
|
2332
2194
|
openMenu,
|
|
2333
2195
|
cellContextMenu,
|
|
2334
|
-
component: ContextMenu ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(ControlledMenu, { anchorPoint: anchorPoint, state: isOpen ?
|
|
2196
|
+
component: ContextMenu ? (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(ControlledMenu, { anchorPoint: anchorPoint, state: isOpen ? 'open' : 'closed', direction: "right", onClose: closeMenu, children: isOpen && (jsxRuntime.jsx(ContextMenu, { selectedRows: selectedRowsRef.current, clickedRow: clickedRowRef.current, colDef: clickedColDefRef.current, close: closeMenu })) }) })) : null,
|
|
2335
2197
|
};
|
|
2336
2198
|
};
|
|
2337
2199
|
|
|
2200
|
+
const GridLoadingOverlayComponentFr = (props, externalRef) => (jsxRuntime.jsx("div", { ref: externalRef, style: {
|
|
2201
|
+
left: 0,
|
|
2202
|
+
top: 0,
|
|
2203
|
+
bottom: 0,
|
|
2204
|
+
right: 0,
|
|
2205
|
+
position: 'absolute',
|
|
2206
|
+
backgroundColor: 'rgba(255,255,255,0.5)',
|
|
2207
|
+
}, children: jsxRuntime.jsx("div", { style: { height: '100%', position: 'relative' }, children: jsxRuntime.jsx("div", { style: { position: 'absolute', left: 0, top: props.headerRowHeight, right: 0, bottom: 0 }, children: jsxRuntime.jsx(lui.LuiStatusSpinner, {}) }) }) }));
|
|
2208
|
+
const GridLoadingOverlayComponent = React.forwardRef(GridLoadingOverlayComponentFr);
|
|
2209
|
+
const GridNoRowsOverlayFr = (props, externalRef) => {
|
|
2210
|
+
if (props.loading) {
|
|
2211
|
+
return jsxRuntime.jsx(GridLoadingOverlayComponent, { ref: externalRef, headerRowHeight: props.headerRowHeight });
|
|
2212
|
+
}
|
|
2213
|
+
if (props.rowCount === 0) {
|
|
2214
|
+
return jsxRuntime.jsx("div", { ref: externalRef, children: props.noRowsOverlayText ?? 'There are currently no rows' });
|
|
2215
|
+
}
|
|
2216
|
+
if (props.filteredRowCount === 0) {
|
|
2217
|
+
return jsxRuntime.jsx("div", { ref: externalRef, children: props.noRowsMatchingOverlayText ?? 'All rows have been filtered' });
|
|
2218
|
+
}
|
|
2219
|
+
return jsxRuntime.jsx("div", { ref: externalRef });
|
|
2220
|
+
};
|
|
2221
|
+
const GridNoRowsOverlay = React.forwardRef(GridNoRowsOverlayFr);
|
|
2222
|
+
|
|
2338
2223
|
/**
|
|
2339
|
-
*
|
|
2340
|
-
*
|
|
2224
|
+
* Retains last sort order from via <AgGrid postRowSort>.
|
|
2225
|
+
* Then applies this sort until next sort column change.
|
|
2226
|
+
* Handles stale sort, when you edit a row but don't want to re-sort.
|
|
2341
2227
|
*/
|
|
2342
|
-
const
|
|
2343
|
-
const {
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
if
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
const
|
|
2353
|
-
if
|
|
2354
|
-
|
|
2355
|
-
const
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
if (!cell)
|
|
2361
|
-
return;
|
|
2362
|
-
const input = cell.querySelector("input, button");
|
|
2363
|
-
if (!input)
|
|
2228
|
+
const usePostSortRowsHook = ({ setStaleGrid }) => {
|
|
2229
|
+
const { redrawRows } = React.useContext(GridContext);
|
|
2230
|
+
// On first run we need to init the first backed up sort order
|
|
2231
|
+
const initialised = React.useRef(false);
|
|
2232
|
+
// Used to detect sort order has changed since last run
|
|
2233
|
+
const lastSortOrderHash = React.useRef('');
|
|
2234
|
+
// Used to detect if sort order was the same, has the direction changed
|
|
2235
|
+
const previousRowSortIndexRef = React.useRef({});
|
|
2236
|
+
// stale sort is when there's a sort and user edits a row
|
|
2237
|
+
// this applies a class to the div wrapping the grid which in turn adds a * beside the sort arrow
|
|
2238
|
+
const sortWasStale = React.useRef(false);
|
|
2239
|
+
// Previous col sort is stored and reapplied if the sort direction changes on the same column and the sort was stale
|
|
2240
|
+
// As a sort on a stale row should just resort, not change sort direction
|
|
2241
|
+
const previousColSort = React.useRef([]);
|
|
2242
|
+
const previousQuickFilter = React.useRef('');
|
|
2243
|
+
return React.useCallback(({ api, nodes }) => {
|
|
2244
|
+
// Grid is destroyed
|
|
2245
|
+
if (!api)
|
|
2364
2246
|
return;
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2247
|
+
const previousRowSortIndex = previousRowSortIndexRef.current;
|
|
2248
|
+
const hashNode = (node) => {
|
|
2249
|
+
return node ? JSON.stringify(node.data) : '';
|
|
2250
|
+
};
|
|
2251
|
+
const copyCurrentSortSettings = () => api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
|
|
2252
|
+
const backupSortOrder = () => {
|
|
2253
|
+
for (const x in previousRowSortIndex)
|
|
2254
|
+
delete previousRowSortIndex[x];
|
|
2255
|
+
nodes.forEach((node, index) => (previousRowSortIndex[`${node.data.id}`] = { index, hash: hashNode(node) }));
|
|
2256
|
+
};
|
|
2257
|
+
// Check if column is the first sorted column. Note: column is preconfigured to sort its sortIndex is null not 1
|
|
2258
|
+
const isFirstSortColumn = (row) => row.sort && [0, null].includes(row.sortIndex ?? null);
|
|
2259
|
+
const isSameColumnAndDifferentSort = (col1, col2) => col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
|
|
2260
|
+
const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
|
|
2261
|
+
const sortNodesByPreviousSort = () => {
|
|
2262
|
+
nodes.sort((a, b) => (previousRowSortIndex[`${a.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER) -
|
|
2263
|
+
(previousRowSortIndex[`${b.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER));
|
|
2264
|
+
};
|
|
2265
|
+
// On first load copy the current sort
|
|
2266
|
+
if (!initialised.current) {
|
|
2267
|
+
initialised.current = true;
|
|
2268
|
+
previousColSort.current = copyCurrentSortSettings();
|
|
2269
|
+
}
|
|
2270
|
+
const newSortOrder = JSON.stringify(copyCurrentSortSettings());
|
|
2271
|
+
let sortOrderChanged = newSortOrder != lastSortOrderHash.current;
|
|
2272
|
+
const quickFilter = api.getQuickFilter();
|
|
2273
|
+
if (previousQuickFilter.current != quickFilter) {
|
|
2274
|
+
previousQuickFilter.current = quickFilter ?? '';
|
|
2275
|
+
sortOrderChanged = true;
|
|
2276
|
+
}
|
|
2277
|
+
if (lodashEs.isEmpty(previousRowSortIndex)) {
|
|
2278
|
+
backupSortOrder();
|
|
2279
|
+
}
|
|
2280
|
+
if (sortOrderChanged) {
|
|
2281
|
+
const thisFirstCol = copyCurrentSortSettings().find(isFirstSortColumn);
|
|
2282
|
+
const previousFirstCol = previousColSort.current.find(isFirstSortColumn);
|
|
2283
|
+
// Change to sort can be: (in the context of stale sort do...)
|
|
2284
|
+
// - no sort to sorted (do nothing)
|
|
2285
|
+
// - asc to desc (resort as asc, and remove stale sort)
|
|
2286
|
+
// - desc to no sort (resort as desc, and remove stale sort)
|
|
2287
|
+
const wasSortChangedOnSameColumn = previousFirstCol && (!thisFirstCol || isSameColumnAndDifferentSort(previousFirstCol, thisFirstCol));
|
|
2288
|
+
// if sort was stale, and we're here, someone has clicked a stale sort order (^*) in the column header
|
|
2289
|
+
if (sortWasStale.current && wasSortChangedOnSameColumn) {
|
|
2290
|
+
// Sort was an existing priority 1 column
|
|
2291
|
+
// We want to re-sort with the old sort direction and clear stale sort
|
|
2292
|
+
sortWasStale.current = false;
|
|
2293
|
+
setStaleGrid(false);
|
|
2294
|
+
// trigger a recapture of sort order
|
|
2295
|
+
lastSortOrderHash.current = '';
|
|
2296
|
+
restorePreviousSortColumnState();
|
|
2297
|
+
}
|
|
2298
|
+
else {
|
|
2299
|
+
// Sort was on a different column so clear sort and sort like normal
|
|
2300
|
+
if (sortWasStale.current) {
|
|
2301
|
+
sortWasStale.current = false;
|
|
2302
|
+
setStaleGrid(false);
|
|
2303
|
+
}
|
|
2304
|
+
// Columns were sorted so retain the sort
|
|
2305
|
+
backupSortOrder();
|
|
2306
|
+
lastSortOrderHash.current = newSortOrder;
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
else {
|
|
2310
|
+
let firstChangedNodeIndex = -1;
|
|
2311
|
+
let lastNewNode = undefined;
|
|
2312
|
+
let changedRowCount = 0;
|
|
2313
|
+
let newRowCount = 0;
|
|
2314
|
+
let index = 0;
|
|
2315
|
+
for (const node of nodes) {
|
|
2316
|
+
const psr = previousRowSortIndex[`${node.data.id}`];
|
|
2317
|
+
if (psr) {
|
|
2318
|
+
if (psr.hash != hashNode(node)) {
|
|
2319
|
+
if (firstChangedNodeIndex === -1)
|
|
2320
|
+
firstChangedNodeIndex = index;
|
|
2321
|
+
changedRowCount++;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
else {
|
|
2325
|
+
lastNewNode = node;
|
|
2326
|
+
newRowCount++;
|
|
2327
|
+
}
|
|
2328
|
+
index++;
|
|
2329
|
+
}
|
|
2330
|
+
let wasStale = false;
|
|
2331
|
+
if (changedRowCount === 0 && newRowCount === 1) {
|
|
2332
|
+
// insert new row at end
|
|
2333
|
+
const newIndex = index - 1;
|
|
2334
|
+
previousRowSortIndex[`${lastNewNode?.data.id}`] = { index: newIndex, hash: hashNode(lastNewNode) };
|
|
2335
|
+
wasStale = true;
|
|
2336
|
+
}
|
|
2337
|
+
else if (changedRowCount === 2 && newRowCount === 0) {
|
|
2338
|
+
// This must be a swap rows (sometimes it's not, needs further attention)
|
|
2339
|
+
backupSortOrder();
|
|
2340
|
+
wasStale = false;
|
|
2341
|
+
}
|
|
2342
|
+
else if (changedRowCount > 1 && newRowCount === 1) {
|
|
2343
|
+
// This must be a insert so, insert new row near the row that changed
|
|
2344
|
+
previousRowSortIndex[`${lastNewNode?.data.id}`] = {
|
|
2345
|
+
index: firstChangedNodeIndex + 0.5,
|
|
2346
|
+
hash: hashNode(lastNewNode),
|
|
2347
|
+
};
|
|
2348
|
+
wasStale = true;
|
|
2349
|
+
// For some reason AgGrid mis-positions the inserted row.
|
|
2350
|
+
lastNewNode && redrawRows();
|
|
2351
|
+
}
|
|
2352
|
+
else if (changedRowCount == 1 && newRowCount === 0) {
|
|
2353
|
+
// User edited one row so, do nothing, retain sort
|
|
2354
|
+
wasStale = true;
|
|
2355
|
+
}
|
|
2356
|
+
else if (changedRowCount !== 0 || newRowCount != 0) {
|
|
2357
|
+
// too many rows changed, resort
|
|
2358
|
+
backupSortOrder();
|
|
2359
|
+
}
|
|
2360
|
+
if (wasStale) {
|
|
2361
|
+
// Check if the sort order the aggrid passed matches our stale sort order
|
|
2362
|
+
const stillStale = Object.keys(previousRowSortIndex).length != nodes.length ||
|
|
2363
|
+
nodes.some((node, index) => previousRowSortIndex[`${node.data.id}`]?.index !== index);
|
|
2364
|
+
// If we haven't already processed a stale sort then...
|
|
2365
|
+
if (stillStale && !sortWasStale.current) {
|
|
2366
|
+
// backup sort state, so we can restore it when sort is clicked on a stale column
|
|
2367
|
+
previousColSort.current = copyCurrentSortSettings();
|
|
2368
|
+
sortWasStale.current = true;
|
|
2369
|
+
setStaleGrid(true);
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
sortNodesByPreviousSort();
|
|
2373
|
+
}
|
|
2374
|
+
}, [redrawRows, setStaleGrid]);
|
|
2368
2375
|
};
|
|
2369
2376
|
|
|
2370
2377
|
/**
|
|
2371
2378
|
* Wrapper for AgGrid to add commonly used functionality.
|
|
2372
2379
|
*/
|
|
2373
|
-
const Grid = ({
|
|
2380
|
+
const Grid = ({ 'data-testid': dataTestId, defaultPostSort = true, rowSelection = 'multiple', suppressColumnVirtualization = true, theme = 'ag-theme-step-default', sizeColumns = 'auto', selectColumnPinned = null, contextMenuSelectRow = false, singleClickEdit = false, rowData, rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40, ...params }) => {
|
|
2374
2381
|
const { gridReady, gridRenderState, setApis, ensureRowVisible, getFirstRowId, selectRowsById, focusByRowById, ensureSelectedRowIsVisible, autoSizeColumns, sizeColumnsToFit, externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync, isExternalFilterPresent, doesExternalFilterPass, setOnCellEditingComplete, getColDef, showNoRowsOverlay, prePopupOps, stopEditing, } = React.useContext(GridContext);
|
|
2375
2382
|
const { checkUpdating, updatedDep, updatingCols } = React.useContext(GridUpdatingContext);
|
|
2376
2383
|
const gridDivRef = React.useRef(null);
|
|
@@ -2399,20 +2406,20 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2399
2406
|
needsAutoSize.current = true;
|
|
2400
2407
|
return;
|
|
2401
2408
|
}
|
|
2402
|
-
const skipHeader = sizeColumns ===
|
|
2403
|
-
if (sizeColumns ===
|
|
2409
|
+
const skipHeader = sizeColumns === 'auto-skip-headers' && gridRendered === 'rows-visible';
|
|
2410
|
+
if (sizeColumns === 'auto' || skipHeader) {
|
|
2404
2411
|
const result = autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, includeFlex: true });
|
|
2405
2412
|
if (!result) {
|
|
2406
2413
|
needsAutoSize.current = true;
|
|
2407
2414
|
return;
|
|
2408
2415
|
}
|
|
2409
|
-
if (gridRendered ===
|
|
2416
|
+
if (gridRendered === 'empty') {
|
|
2410
2417
|
if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
|
|
2411
2418
|
hasSetContentSizeEmpty.current = true;
|
|
2412
2419
|
params.onContentSize?.(result);
|
|
2413
2420
|
}
|
|
2414
2421
|
}
|
|
2415
|
-
else if (gridRendered ===
|
|
2422
|
+
else if (gridRendered === 'rows-visible') {
|
|
2416
2423
|
if (!hasSetContentSize.current) {
|
|
2417
2424
|
if (lastFullResize.current === result.width) {
|
|
2418
2425
|
hasSetContentSize.current = true;
|
|
@@ -2426,10 +2433,10 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2426
2433
|
}
|
|
2427
2434
|
else {
|
|
2428
2435
|
// It should be impossible to get here
|
|
2429
|
-
console.error(
|
|
2436
|
+
console.error('Unknown value returned from hasGridRendered');
|
|
2430
2437
|
}
|
|
2431
2438
|
}
|
|
2432
|
-
if (sizeColumns !==
|
|
2439
|
+
if (sizeColumns !== 'none') {
|
|
2433
2440
|
sizeColumnsToFit();
|
|
2434
2441
|
}
|
|
2435
2442
|
setAutoSized(true);
|
|
@@ -2448,7 +2455,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2448
2455
|
needsAutoSize.current = true;
|
|
2449
2456
|
}
|
|
2450
2457
|
}
|
|
2451
|
-
if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns ===
|
|
2458
|
+
if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns === 'auto')) {
|
|
2452
2459
|
needsAutoSize.current = false;
|
|
2453
2460
|
setInitialContentSize();
|
|
2454
2461
|
}
|
|
@@ -2490,7 +2497,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2490
2497
|
}
|
|
2491
2498
|
const selectedRows = api.getSelectedRows();
|
|
2492
2499
|
// We don't want to update selected Items if it hasn't changed to prevent excess renders
|
|
2493
|
-
if (params.externalSelectedItems.length
|
|
2500
|
+
if (params.externalSelectedItems.length !== selectedRows.length ||
|
|
2494
2501
|
isNotEmpty(lodashEs.xorBy(selectedRows, params.externalSelectedItems, (row) => row.id))) {
|
|
2495
2502
|
setExternallySelectedItemsAreInSync(false);
|
|
2496
2503
|
params.setExternalSelectedItems([...selectedRows]);
|
|
@@ -2546,14 +2553,14 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2546
2553
|
editable,
|
|
2547
2554
|
cellClassRules: {
|
|
2548
2555
|
...colDef.cellClassRules,
|
|
2549
|
-
|
|
2556
|
+
'GridCell-readonly': (ccp) => !editable(ccp),
|
|
2550
2557
|
},
|
|
2551
2558
|
};
|
|
2552
2559
|
});
|
|
2553
2560
|
return params.selectable || params.onRowDragEnd
|
|
2554
2561
|
? [
|
|
2555
2562
|
{
|
|
2556
|
-
colId:
|
|
2563
|
+
colId: 'selection',
|
|
2557
2564
|
editable: false,
|
|
2558
2565
|
rowDrag: !!params.onRowDragEnd,
|
|
2559
2566
|
minWidth: params.selectable && params.onRowDragEnd ? 76 : 48,
|
|
@@ -2563,12 +2570,12 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2563
2570
|
exportable: false,
|
|
2564
2571
|
},
|
|
2565
2572
|
checkboxSelection: params.selectable,
|
|
2566
|
-
headerClass: params.onRowDragEnd ?
|
|
2567
|
-
headerComponent: rowSelection ===
|
|
2573
|
+
headerClass: params.onRowDragEnd ? 'ag-header-select-draggable' : undefined,
|
|
2574
|
+
headerComponent: rowSelection === 'multiple' ? GridHeaderSelect : null,
|
|
2568
2575
|
suppressHeaderKeyboardEvent: (e) => {
|
|
2569
2576
|
if (!params.selectable)
|
|
2570
2577
|
return false;
|
|
2571
|
-
if ((e.event.key ===
|
|
2578
|
+
if ((e.event.key === 'Enter' || e.event.key === ' ') && !e.event.repeat) {
|
|
2572
2579
|
if (lodashEs.isEmpty(e.api.getSelectedRows())) {
|
|
2573
2580
|
e.api.selectAllFiltered();
|
|
2574
2581
|
}
|
|
@@ -2619,7 +2626,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2619
2626
|
// Don't update while there are spinners
|
|
2620
2627
|
if (!lodashEs.isEmpty(updatingCols()))
|
|
2621
2628
|
return;
|
|
2622
|
-
const skipHeader = sizeColumns ===
|
|
2629
|
+
const skipHeader = sizeColumns === 'auto-skip-headers';
|
|
2623
2630
|
if (hasSetContentSize.current) {
|
|
2624
2631
|
autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
|
|
2625
2632
|
}
|
|
@@ -2649,7 +2656,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2649
2656
|
event.node.setSelected(true, true);
|
|
2650
2657
|
}
|
|
2651
2658
|
// Cell already being edited, so don't re-edit until finished
|
|
2652
|
-
if (checkUpdating([event.colDef.field ??
|
|
2659
|
+
if (checkUpdating([event.colDef.field ?? ''], event.data.id)) {
|
|
2653
2660
|
return;
|
|
2654
2661
|
}
|
|
2655
2662
|
if (event.rowIndex !== null) {
|
|
@@ -2695,11 +2702,11 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2695
2702
|
*/
|
|
2696
2703
|
const onCellKeyPress = React.useCallback((e) => {
|
|
2697
2704
|
const kbe = e.event;
|
|
2698
|
-
if (kbe.key ===
|
|
2705
|
+
if (kbe.key === 'Enter') {
|
|
2699
2706
|
if (!invokeEditAction(e))
|
|
2700
2707
|
startCellEditing(e);
|
|
2701
2708
|
}
|
|
2702
|
-
if (kbe.key ===
|
|
2709
|
+
if (kbe.key === 'Tab') {
|
|
2703
2710
|
// eslint-disable-next-line
|
|
2704
2711
|
prePopupOps();
|
|
2705
2712
|
}
|
|
@@ -2709,14 +2716,14 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2709
2716
|
* but we don't want the non-flex auto-sized columns to "fit" size, so suppressSizeToFit is set to true.
|
|
2710
2717
|
*/
|
|
2711
2718
|
const columnDefsAdjusted = React.useMemo(() => {
|
|
2712
|
-
const adjustColDefOrGroup = (colDef) =>
|
|
2719
|
+
const adjustColDefOrGroup = (colDef) => 'children' in colDef ? adjustGroupColDef(colDef) : adjustColDef(colDef);
|
|
2713
2720
|
const adjustGroupColDef = (colDef) => ({
|
|
2714
2721
|
...colDef,
|
|
2715
2722
|
children: colDef.children.map((colDef) => adjustColDefOrGroup(colDef)),
|
|
2716
2723
|
});
|
|
2717
2724
|
const adjustColDef = (colDef) => ({
|
|
2718
2725
|
...colDef,
|
|
2719
|
-
suppressSizeToFit: (sizeColumns ===
|
|
2726
|
+
suppressSizeToFit: (sizeColumns === 'auto' || sizeColumns === 'auto-skip-headers') && !colDef.flex,
|
|
2720
2727
|
sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
|
|
2721
2728
|
});
|
|
2722
2729
|
return columnDefs.map((colDef) => adjustColDefOrGroup(colDef));
|
|
@@ -2738,8 +2745,8 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2738
2745
|
if (lodashEs.isEmpty(colIds)) {
|
|
2739
2746
|
// Columns to resize?
|
|
2740
2747
|
if (!lodashEs.isEmpty(colIdsEdited.current)) {
|
|
2741
|
-
const skipHeader = sizeColumns ===
|
|
2742
|
-
if (sizeColumns ===
|
|
2748
|
+
const skipHeader = sizeColumns === 'auto-skip-headers';
|
|
2749
|
+
if (sizeColumns === 'auto' || skipHeader) {
|
|
2743
2750
|
lodashEs.defer(() => {
|
|
2744
2751
|
if (hasSetContentSize.current) {
|
|
2745
2752
|
autoSizeColumns({
|
|
@@ -2775,7 +2782,7 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2775
2782
|
* Resize columns to fit if required on window/container resize
|
|
2776
2783
|
*/
|
|
2777
2784
|
const onGridSizeChanged = React.useCallback(() => {
|
|
2778
|
-
if (sizeColumns !==
|
|
2785
|
+
if (sizeColumns !== 'none') {
|
|
2779
2786
|
sizeColumnsToFit();
|
|
2780
2787
|
}
|
|
2781
2788
|
}, [sizeColumns, sizeColumnsToFit]);
|
|
@@ -2791,10 +2798,10 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2791
2798
|
if (colId == null)
|
|
2792
2799
|
return;
|
|
2793
2800
|
switch (e.source) {
|
|
2794
|
-
case
|
|
2801
|
+
case 'uiColumnDragged':
|
|
2795
2802
|
userSizedColIds.current.add(colId);
|
|
2796
2803
|
break;
|
|
2797
|
-
case
|
|
2804
|
+
case 'autosizeColumns':
|
|
2798
2805
|
userSizedColIds.current.delete(colId);
|
|
2799
2806
|
break;
|
|
2800
2807
|
}
|
|
@@ -2816,33 +2823,35 @@ const Grid = ({ "data-testid": dataTestId, defaultPostSort = true, rowSelection
|
|
|
2816
2823
|
}
|
|
2817
2824
|
}
|
|
2818
2825
|
}, []);
|
|
2819
|
-
const onRowDragEnd = React.useCallback(
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2826
|
+
const onRowDragEnd = React.useCallback((event) => {
|
|
2827
|
+
void (async () => {
|
|
2828
|
+
const clientSideRowModel = event.api.getModel();
|
|
2829
|
+
if (event.node.rowIndex != null) {
|
|
2830
|
+
const lastHighlightedRowNode = clientSideRowModel.getLastHighlightedRowNode();
|
|
2831
|
+
const isBelow = lastHighlightedRowNode && lastHighlightedRowNode.highlighted === agGridCommunity.RowHighlightPosition.Below;
|
|
2832
|
+
let targetIndex = event.overIndex;
|
|
2833
|
+
if (event.node.rowIndex > event.overIndex) {
|
|
2834
|
+
targetIndex += isBelow ? 1 : 0;
|
|
2835
|
+
}
|
|
2836
|
+
else {
|
|
2837
|
+
targetIndex += isBelow ? 0 : -1;
|
|
2838
|
+
}
|
|
2839
|
+
const moved = event.node.data;
|
|
2840
|
+
const target = event.overNode?.data;
|
|
2841
|
+
moved.id !== target?.id && //moved over a different row
|
|
2842
|
+
event.node.rowIndex != targetIndex && //moved to a different index
|
|
2843
|
+
params.onRowDragEnd &&
|
|
2844
|
+
(await params.onRowDragEnd(moved, target, targetIndex));
|
|
2830
2845
|
}
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
moved.id !== target?.id && //moved over a different row
|
|
2834
|
-
event.node.rowIndex != targetIndex && //moved to a different index
|
|
2835
|
-
params.onRowDragEnd &&
|
|
2836
|
-
(await params.onRowDragEnd(moved, target, targetIndex));
|
|
2837
|
-
}
|
|
2838
|
-
clientSideRowModel.highlightRowAtPixel(null);
|
|
2846
|
+
clientSideRowModel.highlightRowAtPixel(null);
|
|
2847
|
+
})();
|
|
2839
2848
|
}, [params]);
|
|
2840
2849
|
// This is setting a ref in the GridContext so won't be triggering an update loop
|
|
2841
2850
|
setOnCellEditingComplete(params.onCellEditingComplete);
|
|
2842
2851
|
const headerRowCount = columnDefs.some((c) => c.children) ? 2 : 1;
|
|
2843
|
-
return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx(
|
|
2852
|
+
return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [gridContextMenu.component, jsxRuntime.jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsxRuntime.jsx(agGridReact.AgGridReact, { rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: (params) => `${params.data.id}`, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: () => {
|
|
2844
2853
|
setInitialContentSize();
|
|
2845
|
-
}, onRowDataUpdated: onRowDataChanged, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: { minWidth: 48, ...lodashEs.omit(params.defaultColDef, [
|
|
2854
|
+
}, onRowDataUpdated: onRowDataChanged, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: { minWidth: 48, ...lodashEs.omit(params.defaultColDef, ['editable']) }, columnDefs: columnDefsAdjusted, rowData: rowData, noRowsOverlayComponent: (event) => {
|
|
2846
2855
|
let rowCount = 0;
|
|
2847
2856
|
event.api.forEachNode(() => rowCount++);
|
|
2848
2857
|
return (jsxRuntime.jsx(GridNoRowsOverlay, { loading: !rowData || params.loading === true, rowCount: rowCount, headerRowHeight: headerRowCount * rowHeight, filteredRowCount: event.api.getDisplayedRowCount(), noRowsOverlayText: params.noRowsOverlayText, noRowsMatchingOverlayText: params.noRowsMatchingOverlayText }));
|
|
@@ -2853,18 +2862,20 @@ const GridPopoverContext = React.createContext({
|
|
|
2853
2862
|
anchorRef: { current: null },
|
|
2854
2863
|
saving: false,
|
|
2855
2864
|
setSaving: () => { },
|
|
2856
|
-
colId:
|
|
2857
|
-
field:
|
|
2865
|
+
colId: '',
|
|
2866
|
+
field: '',
|
|
2858
2867
|
value: null,
|
|
2859
2868
|
data: {},
|
|
2860
2869
|
selectedRows: [],
|
|
2861
|
-
updateValue:
|
|
2862
|
-
formatValue: () =>
|
|
2870
|
+
updateValue: () => false,
|
|
2871
|
+
formatValue: () => '! No gridPopoverContextProvider !',
|
|
2863
2872
|
});
|
|
2864
2873
|
const useGridPopoverContext = () => React.useContext(GridPopoverContext);
|
|
2865
2874
|
|
|
2866
|
-
const GridPopoverContextProvider = (
|
|
2875
|
+
const GridPopoverContextProvider = (props2) => {
|
|
2867
2876
|
const { getFilteredSelectedRows, updatingCells } = React.useContext(GridContext);
|
|
2877
|
+
const children = props2.children;
|
|
2878
|
+
const props = props2.props;
|
|
2868
2879
|
const anchorRef = React.useRef(props.eGridCell);
|
|
2869
2880
|
const hasSaved = React.useRef(false);
|
|
2870
2881
|
const [saving, setSaving] = React.useState(false);
|
|
@@ -2873,8 +2884,8 @@ const GridPopoverContextProvider = ({ props, children }) => {
|
|
|
2873
2884
|
const multiEdit = cellEditorParams?.multiEdit ?? false;
|
|
2874
2885
|
// Then item that is clicked on will always be first in the list
|
|
2875
2886
|
const selectedRows = React.useMemo(() => multiEdit ? lodashEs.sortBy(getFilteredSelectedRows(), (row) => row.id !== props.data.id) : [props.data], [getFilteredSelectedRows, multiEdit, props.data]);
|
|
2876
|
-
const field = props.colDef?.field ??
|
|
2877
|
-
const colId = props.colDef?.colId ?? field ??
|
|
2887
|
+
const field = props.colDef?.field ?? '';
|
|
2888
|
+
const colId = props.colDef?.colId ?? field ?? '';
|
|
2878
2889
|
const updateValue = React.useCallback(async (saveFn, tabDirection) => {
|
|
2879
2890
|
if (hasSaved.current)
|
|
2880
2891
|
return true;
|
|
@@ -2896,7 +2907,7 @@ const GridPopoverContextProvider = ({ props, children }) => {
|
|
|
2896
2907
|
};
|
|
2897
2908
|
|
|
2898
2909
|
const GridCellMultiSelectClassRules = {
|
|
2899
|
-
|
|
2910
|
+
'ag-selected-for-edit': (params) => {
|
|
2900
2911
|
const { api, node, colDef } = params;
|
|
2901
2912
|
const cep = colDef.cellEditorSelector
|
|
2902
2913
|
? colDef.cellEditorSelector(params)?.params
|
|
@@ -2910,9 +2921,9 @@ const GridCellMultiSelectClassRules = {
|
|
|
2910
2921
|
},
|
|
2911
2922
|
};
|
|
2912
2923
|
|
|
2913
|
-
const GridIcon = (props) => (jsxRuntime.jsx(lui.LuiIcon, { name: props.icon, title: props.title, alt: props.title, size: props.size ??
|
|
2924
|
+
const GridIcon = (props) => (jsxRuntime.jsx(lui.LuiIcon, { name: props.icon, title: props.title, alt: props.title, size: props.size ?? 'md', className: clsx(`AgGridGenericCellRenderer-${props.icon}Icon`, props.className, props.disabled && 'GridIcon-disabled') }));
|
|
2914
2925
|
|
|
2915
|
-
const GridLoadableCell = () => (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 22, divProps: { className:
|
|
2926
|
+
const GridLoadableCell = () => (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 22, divProps: { className: 'GridLoadableCell-container', role: 'status', 'aria-label': 'Loading' } }));
|
|
2916
2927
|
|
|
2917
2928
|
const GridCellRenderer = (props) => {
|
|
2918
2929
|
const { checkUpdating } = React.useContext(GridUpdatingContext);
|
|
@@ -2923,38 +2934,38 @@ const GridCellRenderer = (props) => {
|
|
|
2923
2934
|
const infoFn = rendererParams?.info;
|
|
2924
2935
|
let infoText = props.data !== undefined && infoFn ? infoFn(props) : undefined;
|
|
2925
2936
|
if (Array.isArray(warningText))
|
|
2926
|
-
warningText = warningText.join(
|
|
2937
|
+
warningText = warningText.join('\n');
|
|
2927
2938
|
if (Array.isArray(infoText))
|
|
2928
|
-
infoText = infoText.join(
|
|
2929
|
-
return checkUpdating(colDef.field ?? colDef.colId ??
|
|
2939
|
+
infoText = infoText.join('\n');
|
|
2940
|
+
return checkUpdating(colDef.field ?? colDef.colId ?? '', props.data.id) ? (jsxRuntime.jsx(GridLoadableCell, {})) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [!!warningText && (jsxRuntime.jsx(GridIcon, { icon: 'ic_warning_outline', title: typeof warningText === 'string' ? warningText : 'Warning' })), !!infoText && jsxRuntime.jsx(GridIcon, { icon: 'ic_info_outline', title: typeof infoText === 'string' ? infoText : 'Info' }), jsxRuntime.jsx("div", { className: 'GridCell-container', children: colDef.cellRendererParams?.originalCellRenderer ? (jsxRuntime.jsx(colDef.cellRendererParams.originalCellRenderer, { ...props })) : (jsxRuntime.jsx("span", { title: props.valueFormatted ?? undefined, children: props.valueFormatted })) }), fnOrVar(colDef.editable, props) && rendererParams?.rightHoverElement && (jsxRuntime.jsx("div", { className: 'GridCell-hoverRight', children: rendererParams?.rightHoverElement }))] }));
|
|
2930
2941
|
};
|
|
2931
2942
|
const suppressCellKeyboardEvents = (e) => {
|
|
2932
2943
|
const shortcutKeys = e.colDef.cellRendererParams?.shortcutKeys ?? {};
|
|
2933
2944
|
const exec = shortcutKeys[e.event.key];
|
|
2934
|
-
if (exec && !e.editing && !e.event.repeat && e.event.type ===
|
|
2945
|
+
if (exec && !e.editing && !e.event.repeat && e.event.type === 'keydown') {
|
|
2935
2946
|
const editable = fnOrVar(e.colDef?.editable, e);
|
|
2936
2947
|
return editable ? (exec(e) ?? true) : true;
|
|
2937
2948
|
}
|
|
2938
2949
|
// It's important that aggrid doesn't trigger edit on enter
|
|
2939
2950
|
// as the incorrect selected rows will be returned
|
|
2940
|
-
return ![
|
|
2951
|
+
return !['ArrowLeft', 'ArrowRight', 'ArrowDown', 'ArrowUp', 'Tab', ' ', 'Home', 'End', 'PageUp', 'PageDown'].includes(e.event.key);
|
|
2941
2952
|
};
|
|
2942
2953
|
const generateFilterGetter = (field, filterValueGetter, valueFormatter) => {
|
|
2943
2954
|
if (filterValueGetter)
|
|
2944
2955
|
return filterValueGetter;
|
|
2945
2956
|
// aggrid will default to valueGetter
|
|
2946
|
-
if (typeof valueFormatter !==
|
|
2957
|
+
if (typeof valueFormatter !== 'function' || !field)
|
|
2947
2958
|
return undefined;
|
|
2948
2959
|
return (params) => {
|
|
2949
2960
|
const value = params.getValue(field);
|
|
2950
2961
|
let formattedValue = valueFormatter({ ...params, value });
|
|
2951
2962
|
// Search for null values using standard dash
|
|
2952
|
-
if (formattedValue ===
|
|
2953
|
-
formattedValue +=
|
|
2963
|
+
if (formattedValue === '–')
|
|
2964
|
+
formattedValue += ' -';
|
|
2954
2965
|
// Search by raw value as well as formatted
|
|
2955
|
-
const gotValue = [
|
|
2956
|
-
return (formattedValue + (gotValue != null && formattedValue != gotValue ?
|
|
2957
|
-
.replace(/\s+/g,
|
|
2966
|
+
const gotValue = ['string', 'number'].includes(typeof value) ? value : undefined;
|
|
2967
|
+
return (formattedValue + (gotValue != null && formattedValue != gotValue ? ' ' + gotValue : '')) //
|
|
2968
|
+
.replace(/\s+/g, ' ')
|
|
2958
2969
|
.trim();
|
|
2959
2970
|
};
|
|
2960
2971
|
};
|
|
@@ -2997,15 +3008,15 @@ const GridCell = (props, custom) => {
|
|
|
2997
3008
|
// Default value formatter, otherwise react freaks out on objects
|
|
2998
3009
|
valueFormatter: (params) => {
|
|
2999
3010
|
if (params.value == null)
|
|
3000
|
-
return
|
|
3001
|
-
const types = [
|
|
3011
|
+
return '–';
|
|
3012
|
+
const types = ['number', 'boolean', 'string'];
|
|
3002
3013
|
if (types.includes(typeof params.value))
|
|
3003
3014
|
return `${params.value}`;
|
|
3004
3015
|
else
|
|
3005
3016
|
return JSON.stringify(params.value);
|
|
3006
3017
|
},
|
|
3007
3018
|
...props,
|
|
3008
|
-
cellRenderer: typeof props.cellRenderer ===
|
|
3019
|
+
cellRenderer: typeof props.cellRenderer === 'string' ? props.cellRenderer : GridCellRenderer,
|
|
3009
3020
|
cellRendererParams: {
|
|
3010
3021
|
originalCellRenderer: props.cellRenderer,
|
|
3011
3022
|
...props.cellRendererParams,
|
|
@@ -3021,16 +3032,16 @@ const GenericCellEditorComponentWrapper = (editor) => {
|
|
|
3021
3032
|
return React.forwardRef(function GenericCellEditorComponentFr(cellEditorParams, _) {
|
|
3022
3033
|
const valueFormatted = cellEditorParams.formatValue
|
|
3023
3034
|
? cellEditorParams.formatValue(cellEditorParams.value)
|
|
3024
|
-
:
|
|
3025
|
-
return (jsxRuntime.
|
|
3035
|
+
: 'Missing formatter';
|
|
3036
|
+
return (jsxRuntime.jsx(GridPopoverContextProvider, { props: cellEditorParams, children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(cellEditorParams.colDef.cellRenderer, { ...cellEditorParams, valueFormatted: valueFormatted, ...cellEditorParams.colDef.cellRendererParams }), obj.editor && jsxRuntime.jsx(obj.editor, { ...cellEditorParams })] }) }));
|
|
3026
3037
|
});
|
|
3027
3038
|
};
|
|
3028
3039
|
|
|
3029
|
-
const GridCellFillerColId =
|
|
3040
|
+
const GridCellFillerColId = 'gridCellFiller';
|
|
3030
3041
|
const isGridCellFiller = (col) => col.colId === GridCellFillerColId;
|
|
3031
3042
|
const GridCellFiller = () => ({
|
|
3032
3043
|
colId: GridCellFillerColId,
|
|
3033
|
-
headerName:
|
|
3044
|
+
headerName: '',
|
|
3034
3045
|
flex: 1,
|
|
3035
3046
|
});
|
|
3036
3047
|
|
|
@@ -3048,8 +3059,27 @@ const GridCellMultiEditor = (props, cellEditorSelector) => GridCell({
|
|
|
3048
3059
|
...props,
|
|
3049
3060
|
});
|
|
3050
3061
|
|
|
3051
|
-
const
|
|
3052
|
-
|
|
3062
|
+
const useGridFilter = (filter) => {
|
|
3063
|
+
const { addExternalFilter, removeExternalFilter } = React.useContext(GridContext);
|
|
3064
|
+
React.useEffect(() => {
|
|
3065
|
+
const thisFilter = filter;
|
|
3066
|
+
thisFilter && addExternalFilter(thisFilter);
|
|
3067
|
+
return () => {
|
|
3068
|
+
thisFilter && removeExternalFilter(thisFilter);
|
|
3069
|
+
};
|
|
3070
|
+
}, [addExternalFilter, filter, removeExternalFilter]);
|
|
3071
|
+
};
|
|
3072
|
+
|
|
3073
|
+
const GridFilterButtons = ({ className, luiButtonProps, options, }) => {
|
|
3074
|
+
// Select defaultSelected option, otherwise first option. If no options select none.
|
|
3075
|
+
const [selectedOption, setSelectedOption] = React.useState(options.find((option) => option.defaultSelected) ?? options[0]);
|
|
3076
|
+
const filter = React.useMemo(() => selectedOption?.filter, [selectedOption]);
|
|
3077
|
+
useGridFilter(filter);
|
|
3078
|
+
return (jsxRuntime.jsx("div", { className: clsx(className, 'flex-col-center'), children: jsxRuntime.jsx(lui.LuiButtonGroup, { children: options.map((option, index) => (jsxRuntime.jsx(lui.LuiButton, { ...luiButtonProps, className: clsx(`lui-button lui-button-secondary`, selectedOption?.label === option.label && `lui-button-active`, luiButtonProps?.className), onClick: () => setSelectedOption(option), children: option.label }, `${index}`))) }) }));
|
|
3079
|
+
};
|
|
3080
|
+
|
|
3081
|
+
const GridFilterHeaderIconButton = React.forwardRef(function columnsButton({ icon, title, onClick, buttonProps, disabled = false, size = 'md' }, ref) {
|
|
3082
|
+
return (jsxRuntime.jsx(lui.LuiButton, { ...buttonProps, type: 'button', level: 'tertiary', className: 'lui-button-icon-only', ref: ref, buttonProps: { 'aria-label': title }, title: title, onClick: onClick, disabled: disabled, children: jsxRuntime.jsx(lui.LuiIcon, { name: icon, alt: 'Menu', size: size }) }));
|
|
3053
3083
|
});
|
|
3054
3084
|
|
|
3055
3085
|
const GridFilterColumnsToggle = ({ saveState = true }) => {
|
|
@@ -3057,9 +3087,9 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
|
|
|
3057
3087
|
const { getColumns, getColumnIds, invisibleColumnIds, setInvisibleColumnIds } = React.useContext(GridContext);
|
|
3058
3088
|
const columnStorageKey = React.useMemo(() => lodashEs.isEmpty(getColumnIds())
|
|
3059
3089
|
? null // Grid hasn't been initialised yet
|
|
3060
|
-
:
|
|
3090
|
+
: 'stepAgGrid_invisibleColumnIds_' + getColumnIds().join('_'), [getColumnIds]);
|
|
3061
3091
|
// infer the invisible ids from colDefs
|
|
3062
|
-
const resetColumns = React.useCallback(() => setInvisibleColumnIds(getColumnIds(
|
|
3092
|
+
const resetColumns = React.useCallback(() => setInvisibleColumnIds(getColumnIds('initialHide')), [getColumnIds, setInvisibleColumnIds]);
|
|
3063
3093
|
// Load state on start
|
|
3064
3094
|
React.useEffect(() => {
|
|
3065
3095
|
if (!columnStorageKey || loaded)
|
|
@@ -3071,11 +3101,11 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
|
|
|
3071
3101
|
resetColumns();
|
|
3072
3102
|
}
|
|
3073
3103
|
else {
|
|
3074
|
-
const invisibleIds = JSON.parse(stored ??
|
|
3104
|
+
const invisibleIds = JSON.parse(stored ?? '[]');
|
|
3075
3105
|
if (!Array.isArray(invisibleIds)) {
|
|
3076
3106
|
console.error(`stored invisible ids not an array: ${stored}`);
|
|
3077
3107
|
}
|
|
3078
|
-
else if (!invisibleIds.every((id) => typeof id ===
|
|
3108
|
+
else if (!invisibleIds.every((id) => typeof id === 'string')) {
|
|
3079
3109
|
console.error(`stored invisible ids not strings: ${stored}`);
|
|
3080
3110
|
}
|
|
3081
3111
|
else {
|
|
@@ -3105,15 +3135,15 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
|
|
|
3105
3135
|
}, [invisibleColumnIds, setInvisibleColumnIds]);
|
|
3106
3136
|
const numericRegExp = /^\d+$/;
|
|
3107
3137
|
const isNonManageableColumn = (col) => col.lockVisible || col.colId == null || numericRegExp.test(col.colId);
|
|
3108
|
-
return (jsxRuntime.jsxs(Menu, { menuButton: jsxRuntime.jsx(GridFilterHeaderIconButton, { icon:
|
|
3138
|
+
return (jsxRuntime.jsxs(Menu, { menuButton: jsxRuntime.jsx(GridFilterHeaderIconButton, { icon: 'ic_columns', title: 'Column visibility' }), menuClassName: 'step-ag-grid-react-menu', portal: true, unmountOnClose: true, children: [jsxRuntime.jsx("div", { className: 'GridFilterColumnsToggle-container', children: getColumns('headerName').map((col) => (jsxRuntime.jsx(MenuItem, { disabled: isNonManageableColumn(col), onClick: (e) => {
|
|
3109
3139
|
// Global react-menu MenuItem handler handles tabs
|
|
3110
|
-
if (e.key !==
|
|
3140
|
+
if (e.key !== 'Tab') {
|
|
3111
3141
|
e.keepOpen = true;
|
|
3112
|
-
if (e.key !==
|
|
3142
|
+
if (e.key !== 'Enter') {
|
|
3113
3143
|
toggleColumn(col.colId);
|
|
3114
3144
|
}
|
|
3115
3145
|
}
|
|
3116
|
-
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: !!invisibleColumnIds && !invisibleColumnIds.includes(col.colId ??
|
|
3146
|
+
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: !!invisibleColumnIds && !invisibleColumnIds.includes(col.colId ?? ''), value: `${col.colId}`, label: col.headerName ?? '', isDisabled: isNonManageableColumn(col), inputProps: {
|
|
3117
3147
|
onClick: (e) => {
|
|
3118
3148
|
// Click is handled by MenuItem onClick so keyboard events work
|
|
3119
3149
|
e.preventDefault();
|
|
@@ -3121,47 +3151,15 @@ const GridFilterColumnsToggle = ({ saveState = true }) => {
|
|
|
3121
3151
|
},
|
|
3122
3152
|
}, onChange: () => {
|
|
3123
3153
|
/*Do nothing, change handled by menuItem*/
|
|
3124
|
-
} }) }, col.colId ??
|
|
3154
|
+
} }) }, col.colId ?? 'no_col_id'))) }), jsxRuntime.jsx(MenuDivider, {}, `$$divider_reset_columns`), jsxRuntime.jsxs(MenuItem, { onClick: (e) => {
|
|
3125
3155
|
// Global react-menu MenuItem handler handles tabs
|
|
3126
|
-
if (e.key !==
|
|
3127
|
-
e.keepOpen = e.key !==
|
|
3156
|
+
if (e.key !== 'Tab') {
|
|
3157
|
+
e.keepOpen = e.key !== 'Enter';
|
|
3128
3158
|
resetColumns();
|
|
3129
3159
|
}
|
|
3130
|
-
}, children: [jsxRuntime.jsx(lui.LuiIcon, { name:
|
|
3131
|
-
};
|
|
3132
|
-
|
|
3133
|
-
const useGridFilter = (filter) => {
|
|
3134
|
-
const { addExternalFilter, removeExternalFilter } = React.useContext(GridContext);
|
|
3135
|
-
React.useEffect(() => {
|
|
3136
|
-
const thisFilter = filter;
|
|
3137
|
-
thisFilter && addExternalFilter(thisFilter);
|
|
3138
|
-
return () => {
|
|
3139
|
-
thisFilter && removeExternalFilter(thisFilter);
|
|
3140
|
-
};
|
|
3141
|
-
}, [addExternalFilter, filter, removeExternalFilter]);
|
|
3142
|
-
};
|
|
3143
|
-
|
|
3144
|
-
const GridFilterButtons = ({ className, luiButtonProps, options, }) => {
|
|
3145
|
-
// Select defaultSelected option, otherwise first option. If no options select none.
|
|
3146
|
-
const [selectedOption, setSelectedOption] = React.useState(options.find((option) => option.defaultSelected) ?? options[0]);
|
|
3147
|
-
const filter = React.useMemo(() => selectedOption?.filter, [selectedOption]);
|
|
3148
|
-
useGridFilter(filter);
|
|
3149
|
-
return (jsxRuntime.jsx("div", { className: clsx(className, "flex-col-center"), children: jsxRuntime.jsx(lui.LuiButtonGroup, { children: options.map((option, index) => (jsxRuntime.jsx(lui.LuiButton, { ...luiButtonProps, className: clsx(`lui-button lui-button-secondary`, selectedOption?.label === option.label && `lui-button-active`, luiButtonProps?.className), onClick: () => setSelectedOption(option), children: option.label }, `${index}`))) }) }));
|
|
3150
|
-
};
|
|
3151
|
-
|
|
3152
|
-
const GridFilterQuick = ({ quickFilterPlaceholder, defaultValue }) => {
|
|
3153
|
-
const { setQuickFilter } = React.useContext(GridContext);
|
|
3154
|
-
const [quickFilterValue, setQuickFilterValue] = React.useState(defaultValue ?? "");
|
|
3155
|
-
React.useEffect(() => {
|
|
3156
|
-
setQuickFilter(quickFilterValue);
|
|
3157
|
-
}, [quickFilterValue, setQuickFilter]);
|
|
3158
|
-
return (jsxRuntime.jsxs("div", { className: "GridFilterQuick-container", children: [jsxRuntime.jsx("div", { className: "GridFilterQuick-icon", children: jsxRuntime.jsx(lui.LuiIcon, { name: "ic_search", alt: "Search", size: "md" }) }), jsxRuntime.jsx("input", { "aria-label": "Search", className: "GridFilterQuick-input", type: "text", placeholder: quickFilterPlaceholder ?? "Search", value: quickFilterValue, onChange: (event) => {
|
|
3159
|
-
setQuickFilterValue(event.target.value);
|
|
3160
|
-
} })] }));
|
|
3160
|
+
}, children: [jsxRuntime.jsx(lui.LuiIcon, { name: 'ic_regenerate', alt: 'Reset columns', size: 'md', className: 'MenuItem-icon' }), "Reset columns"] }, '$$reset_columns')] }));
|
|
3161
3161
|
};
|
|
3162
3162
|
|
|
3163
|
-
const GridFilters = ({ children }) => (jsxRuntime.jsx("div", { className: "Grid-container-filters", children: children }));
|
|
3164
|
-
|
|
3165
3163
|
/**
|
|
3166
3164
|
* Cancels timeouts on scope being destroyed.
|
|
3167
3165
|
*
|
|
@@ -3228,12 +3226,25 @@ const GridFilterDownloadCsvButton = (csvExportParams) => {
|
|
|
3228
3226
|
}, 100);
|
|
3229
3227
|
};
|
|
3230
3228
|
return downloading ? (jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 22, divProps: {
|
|
3231
|
-
role:
|
|
3232
|
-
[
|
|
3233
|
-
style: { width: 42, display:
|
|
3234
|
-
} })) : (jsxRuntime.jsx(GridFilterHeaderIconButton, { icon:
|
|
3229
|
+
role: 'status',
|
|
3230
|
+
['aria-label']: 'Downloading...',
|
|
3231
|
+
style: { width: 42, display: 'flex', justifyContent: 'center' },
|
|
3232
|
+
} })) : (jsxRuntime.jsx(GridFilterHeaderIconButton, { icon: 'ic_csv_file', title: 'Download CSV', onClick: handleDownloadClick, disabled: downloading }));
|
|
3233
|
+
};
|
|
3234
|
+
|
|
3235
|
+
const GridFilterQuick = ({ quickFilterPlaceholder, defaultValue }) => {
|
|
3236
|
+
const { setQuickFilter } = React.useContext(GridContext);
|
|
3237
|
+
const [quickFilterValue, setQuickFilterValue] = React.useState(defaultValue ?? '');
|
|
3238
|
+
React.useEffect(() => {
|
|
3239
|
+
setQuickFilter(quickFilterValue);
|
|
3240
|
+
}, [quickFilterValue, setQuickFilter]);
|
|
3241
|
+
return (jsxRuntime.jsxs("div", { className: "GridFilterQuick-container", children: [jsxRuntime.jsx("div", { className: "GridFilterQuick-icon", children: jsxRuntime.jsx(lui.LuiIcon, { name: 'ic_search', alt: 'Search', size: 'md' }) }), jsxRuntime.jsx("input", { "aria-label": "Search", className: "GridFilterQuick-input", type: "text", placeholder: quickFilterPlaceholder ?? 'Search', value: quickFilterValue, onChange: (event) => {
|
|
3242
|
+
setQuickFilterValue(event.target.value);
|
|
3243
|
+
} })] }));
|
|
3235
3244
|
};
|
|
3236
3245
|
|
|
3246
|
+
const GridFilters = ({ children }) => (jsxRuntime.jsx("div", { className: "Grid-container-filters", children: children }));
|
|
3247
|
+
|
|
3237
3248
|
/* global setTimeout, clearTimeout */
|
|
3238
3249
|
|
|
3239
3250
|
var dist = function debounce(fn) {
|
|
@@ -3309,16 +3320,17 @@ function defer() {
|
|
|
3309
3320
|
var debounce = /*@__PURE__*/getDefaultExportFromCjs(dist);
|
|
3310
3321
|
|
|
3311
3322
|
const GridSubComponentContext = React.createContext({
|
|
3312
|
-
value:
|
|
3323
|
+
value: 'GridSubComponentContext value no context',
|
|
3313
3324
|
data: {},
|
|
3314
3325
|
setValue: () => {
|
|
3315
|
-
console.error(
|
|
3326
|
+
console.error('GridSubComponentContext setValue no context');
|
|
3316
3327
|
},
|
|
3317
3328
|
setValid: () => {
|
|
3318
|
-
console.error(
|
|
3329
|
+
console.error('GridSubComponentContext setValid no context');
|
|
3319
3330
|
},
|
|
3331
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
3320
3332
|
triggerSave: async () => {
|
|
3321
|
-
console.error(
|
|
3333
|
+
console.error('GridSubComponentContext triggerSave no context');
|
|
3322
3334
|
},
|
|
3323
3335
|
context: null,
|
|
3324
3336
|
});
|
|
@@ -3354,7 +3366,7 @@ var css_248z$2 = ".FormError{display:flex}.FormError-helpText{color:#6b6966;font
|
|
|
3354
3366
|
styleInject(css_248z$2);
|
|
3355
3367
|
|
|
3356
3368
|
const FormError = (props) => {
|
|
3357
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.error && (jsxRuntime.jsxs("div", { className: "FormError", children: [jsxRuntime.jsx(lui.LuiIcon, { alt: "error", name: "ic_error", className: "FormError-text-icon", size: "sm", status: "error" }), jsxRuntime.jsx("span", { className: "FormError-error", children: props.error })] })), props.helpText && !props.error && jsxRuntime.jsx("span", { className:
|
|
3369
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.error && (jsxRuntime.jsxs("div", { className: "FormError", children: [jsxRuntime.jsx(lui.LuiIcon, { alt: "error", name: "ic_error", className: "FormError-text-icon", size: "sm", status: "error" }), jsxRuntime.jsx("span", { className: "FormError-error", children: props.error })] })), props.helpText && !props.error && jsxRuntime.jsx("span", { className: 'FormError-helpText', children: props.helpText })] }));
|
|
3358
3370
|
};
|
|
3359
3371
|
|
|
3360
3372
|
function escapeStringRegexp(string) {
|
|
@@ -3494,18 +3506,18 @@ const textMatch = (text, filter) => {
|
|
|
3494
3506
|
if (text == null)
|
|
3495
3507
|
return true;
|
|
3496
3508
|
const superFilters = filter
|
|
3497
|
-
.split(
|
|
3509
|
+
.split(',')
|
|
3498
3510
|
.map((sf) => sf.trim())
|
|
3499
3511
|
.filter((sf) => sf)
|
|
3500
3512
|
.map((r) => r
|
|
3501
3513
|
.split(/\s+/)
|
|
3502
|
-
.map((f) => (f.startsWith(
|
|
3503
|
-
.join(
|
|
3504
|
-
const [negativeFilters, positiveFilters] = lodashEs.partition(superFilters, (superFilters) => superFilters.startsWith(
|
|
3505
|
-
const values = text.replaceAll(
|
|
3514
|
+
.map((f) => (f.startsWith('=') ? f.slice(1) : f + '*'))
|
|
3515
|
+
.join(' '));
|
|
3516
|
+
const [negativeFilters, positiveFilters] = lodashEs.partition(superFilters, (superFilters) => superFilters.startsWith('!'));
|
|
3517
|
+
const values = text.replaceAll(',', ' ').trim().split(/\s+/);
|
|
3506
3518
|
return ((lodashEs.isEmpty(positiveFilters) || // Not filtered
|
|
3507
3519
|
positiveFilters.some((superFilter) => {
|
|
3508
|
-
const subFilters = superFilter.split(/\s+/).map((s) => s.replaceAll(/([!?])/g,
|
|
3520
|
+
const subFilters = superFilter.split(/\s+/).map((s) => s.replaceAll(/([!?])/g, '\\$1'));
|
|
3509
3521
|
return subFilters.every((subFilter) => values.some((value) => isMatch(value, subFilter)));
|
|
3510
3522
|
})) &&
|
|
3511
3523
|
(lodashEs.isEmpty(negativeFilters) ||
|
|
@@ -3542,19 +3554,19 @@ const useGridPopoverHook = (props) => {
|
|
|
3542
3554
|
}
|
|
3543
3555
|
}, [cancelEdit, props, stopEditing, updateValue]);
|
|
3544
3556
|
const popoverWrapper = React.useCallback((children) => {
|
|
3545
|
-
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: anchorRef.current && (jsxRuntime.jsxs(ControlledMenu, { state: isOpen ?
|
|
3557
|
+
return (jsxRuntime.jsx(jsxRuntime.Fragment, { children: anchorRef.current && (jsxRuntime.jsxs(ControlledMenu, { state: isOpen ? 'open' : 'closed', portal: true, unmountOnClose: true, anchorRef: anchorRef, saveButtonRef: saveButtonRef, menuClassName: 'step-ag-grid-react-menu', onClose: (event) => {
|
|
3546
3558
|
// Prevent menu from closing when modals are invoked
|
|
3547
3559
|
if (event.reason === CloseReason.BLUR)
|
|
3548
3560
|
return;
|
|
3549
|
-
triggerSave(event.reason)
|
|
3550
|
-
}, viewScroll:
|
|
3551
|
-
jsxRuntime.jsx("div", { className:
|
|
3552
|
-
let reason = e.currentTarget.getAttribute(
|
|
3561
|
+
void triggerSave(event.reason);
|
|
3562
|
+
}, viewScroll: 'auto', dontShrinkIfDirectionIsTop: true, className: props.className, children: [saving && ( // This is the overlay that prevents editing when the editor is saving
|
|
3563
|
+
jsxRuntime.jsx("div", { className: 'ComponentLoadingWrapper-saveOverlay' })), children, jsxRuntime.jsx("button", { ref: saveButtonRef, "data-reason": '', onClick: (e) => {
|
|
3564
|
+
let reason = e.currentTarget.getAttribute('data-reason') ?? undefined;
|
|
3553
3565
|
if (props.dontSaveOnExternalClick && reason === CloseReason.BLUR) {
|
|
3554
3566
|
reason = CloseReason.CANCEL;
|
|
3555
3567
|
}
|
|
3556
|
-
triggerSave(reason)
|
|
3557
|
-
}, style: { display:
|
|
3568
|
+
void triggerSave(reason);
|
|
3569
|
+
}, style: { display: 'none' } })] })) }));
|
|
3558
3570
|
}, [anchorRef, isOpen, props.className, props.dontSaveOnExternalClick, saving, triggerSave]);
|
|
3559
3571
|
return {
|
|
3560
3572
|
popoverWrapper,
|
|
@@ -3562,19 +3574,19 @@ const useGridPopoverHook = (props) => {
|
|
|
3562
3574
|
};
|
|
3563
3575
|
};
|
|
3564
3576
|
|
|
3565
|
-
const MenuSeparatorString =
|
|
3577
|
+
const MenuSeparatorString = '_____MENU_SEPARATOR_____';
|
|
3566
3578
|
const MenuSeparator = Object.freeze({ value: MenuSeparatorString });
|
|
3567
|
-
const MenuHeaderString =
|
|
3579
|
+
const MenuHeaderString = '_____MENU_HEADER_____';
|
|
3568
3580
|
const MenuHeaderItem = (title) => {
|
|
3569
3581
|
return { label: title, value: MenuHeaderString };
|
|
3570
3582
|
};
|
|
3571
3583
|
const fieldToString = (field) => {
|
|
3572
|
-
return typeof field
|
|
3584
|
+
return typeof field === 'symbol' ? field.toString() : `${field}`;
|
|
3573
3585
|
};
|
|
3574
3586
|
const GridFormDropDown = (props) => {
|
|
3575
3587
|
const { selectedRows, field, data } = useGridPopoverContext();
|
|
3576
3588
|
// Save triggers during async action processing which triggers another selectItem(), this ref blocks that
|
|
3577
|
-
const [filter, setFilter] = React.useState(props.filterDefaultValue ??
|
|
3589
|
+
const [filter, setFilter] = React.useState(props.filterDefaultValue ?? '');
|
|
3578
3590
|
const [filteredValues, setFilteredValues] = React.useState();
|
|
3579
3591
|
const [options, setOptions] = React.useState(null);
|
|
3580
3592
|
const subComponentIsValid = React.useRef(false);
|
|
@@ -3605,12 +3617,12 @@ const GridFormDropDown = (props) => {
|
|
|
3605
3617
|
if (options)
|
|
3606
3618
|
return;
|
|
3607
3619
|
let optionsConf = props.options;
|
|
3608
|
-
(async () => {
|
|
3609
|
-
if (typeof optionsConf
|
|
3620
|
+
void (async () => {
|
|
3621
|
+
if (typeof optionsConf === 'function') {
|
|
3610
3622
|
optionsConf = await optionsConf(selectedRows, filter);
|
|
3611
3623
|
}
|
|
3612
3624
|
if (optionsConf !== undefined) {
|
|
3613
|
-
const optionsList = optionsConf?.map((item) => item == null || typeof item
|
|
3625
|
+
const optionsList = optionsConf?.map((item) => item == null || typeof item === 'string'
|
|
3614
3626
|
? {
|
|
3615
3627
|
value: item,
|
|
3616
3628
|
label: item,
|
|
@@ -3623,16 +3635,16 @@ const GridFormDropDown = (props) => {
|
|
|
3623
3635
|
}, [filter, options, props, selectedRows]);
|
|
3624
3636
|
// Local filtering.
|
|
3625
3637
|
React.useEffect(() => {
|
|
3626
|
-
if (props.filtered ==
|
|
3638
|
+
if (props.filtered == 'local') {
|
|
3627
3639
|
if (options == null)
|
|
3628
3640
|
return;
|
|
3629
3641
|
setFilteredValues(options
|
|
3630
3642
|
.map((option) => {
|
|
3631
|
-
if (option.label != null && typeof option.label !==
|
|
3632
|
-
console.error(
|
|
3643
|
+
if (option.label != null && typeof option.label !== 'string') {
|
|
3644
|
+
console.error('Cannot filter non-string labels', option);
|
|
3633
3645
|
return undefined;
|
|
3634
3646
|
}
|
|
3635
|
-
return textMatch(option.label ||
|
|
3647
|
+
return textMatch(option.label || '', filter) ? option : undefined;
|
|
3636
3648
|
})
|
|
3637
3649
|
.filter((r) => r !== undefined));
|
|
3638
3650
|
}
|
|
@@ -3643,9 +3655,9 @@ const GridFormDropDown = (props) => {
|
|
|
3643
3655
|
const previousFilter = React.useRef(filter);
|
|
3644
3656
|
// Reload filtering.
|
|
3645
3657
|
React.useEffect(() => {
|
|
3646
|
-
if (previousFilter.current != filter && props.filtered ==
|
|
3658
|
+
if (previousFilter.current != filter && props.filtered == 'reload') {
|
|
3647
3659
|
previousFilter.current = filter;
|
|
3648
|
-
reSearchOnFilterChange()
|
|
3660
|
+
void reSearchOnFilterChange();
|
|
3649
3661
|
}
|
|
3650
3662
|
}, [filter, props, reSearchOnFilterChange]);
|
|
3651
3663
|
/**
|
|
@@ -3683,12 +3695,12 @@ const GridFormDropDown = (props) => {
|
|
|
3683
3695
|
});
|
|
3684
3696
|
let lastHeader = null;
|
|
3685
3697
|
let showHeader = null;
|
|
3686
|
-
return popoverWrapper(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.filtered && (jsxRuntime.jsxs("div", { className:
|
|
3698
|
+
return popoverWrapper(jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.filtered && (jsxRuntime.jsxs("div", { className: 'GridFormDropDown-filter', children: [jsxRuntime.jsx(FocusableItem, { className: 'filter-item', onFocus: () => {
|
|
3687
3699
|
setSelectedItem(null);
|
|
3688
3700
|
setSubSelectedValue(null);
|
|
3689
3701
|
subComponentIsValid.current = true;
|
|
3690
|
-
}, children: ({ ref }) => (jsxRuntime.jsxs("div", { style: { display:
|
|
3691
|
-
!(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value) }), props.filterHelpText && isNotEmpty(filter) && (jsxRuntime.jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsxRuntime.jsx(MenuDivider, {}, `$$divider_filter`)] })), jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className:
|
|
3702
|
+
}, children: ({ ref }) => (jsxRuntime.jsxs("div", { style: { display: 'flex', flexDirection: 'column', width: '100%' }, children: [jsxRuntime.jsx("input", { className: 'LuiTextInput-input', ref: ref, type: "text", placeholder: props.filterPlaceholder ?? 'Filter...', "data-testid": 'filteredMenu-free-text-input', defaultValue: filter, "data-allowtabtosave": true, "data-disableenterautosave": !props.onSelectFilter &&
|
|
3703
|
+
!(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent), onChange: (e) => setFilter(e.target.value) }), props.filterHelpText && isNotEmpty(filter) && (jsxRuntime.jsx(FormError, { error: null, helpText: props.filterHelpText }))] })) }), jsxRuntime.jsx(MenuDivider, {}, `$$divider_filter`)] })), jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormDropDown-options', children: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [options && (lodashEs.isEmpty(options) || (filteredValues && lodashEs.isEmpty(filteredValues))) && (jsxRuntime.jsx(MenuItem, { className: 'GridPopoverEditDropDown-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, `${fieldToString(field)}-empty`)), options?.map((item, index) => {
|
|
3692
3704
|
showHeader = null;
|
|
3693
3705
|
if (item.value === MenuSeparatorString) {
|
|
3694
3706
|
return jsxRuntime.jsx(MenuDivider, {}, `$$divider_${index}`);
|
|
@@ -3703,7 +3715,7 @@ const GridFormDropDown = (props) => {
|
|
|
3703
3715
|
lastHeader = null;
|
|
3704
3716
|
}
|
|
3705
3717
|
}
|
|
3706
|
-
return ((!filteredValues || filteredValues.includes(item)) && (jsxRuntime.jsxs(React.Fragment, { children: [showHeader, jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs(MenuItem, { disabled: !!item.disabled, title: item.disabled && typeof item.disabled !==
|
|
3718
|
+
return ((!filteredValues || filteredValues.includes(item)) && (jsxRuntime.jsxs(React.Fragment, { children: [showHeader, jsxRuntime.jsxs("div", { children: [jsxRuntime.jsxs(MenuItem, { disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', value: item.value, onFocus: () => {
|
|
3707
3719
|
if (selectedItem !== item) {
|
|
3708
3720
|
setSelectedItem(item);
|
|
3709
3721
|
setSubSelectedValue(null);
|
|
@@ -3714,7 +3726,7 @@ const GridFormDropDown = (props) => {
|
|
|
3714
3726
|
}
|
|
3715
3727
|
}, onClick: (e) => {
|
|
3716
3728
|
e.keepOpen = !!item.subComponent;
|
|
3717
|
-
}, children: [item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`), item.subComponent ?
|
|
3729
|
+
}, children: [item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`), item.subComponent ? '...' : ''] }, `${fieldToString(field)}-${index}`), item.subComponent && selectedItem === item && (jsxRuntime.jsx(FocusableItem, { className: 'LuiDeprecatedForms', children: () => (jsxRuntime.jsx(GridSubComponentContext.Provider, { value: {
|
|
3718
3730
|
context: { options },
|
|
3719
3731
|
data,
|
|
3720
3732
|
value: subSelectedValue,
|
|
@@ -3731,7 +3743,7 @@ const GridFormDropDown = (props) => {
|
|
|
3731
3743
|
triggerSave: async () => {
|
|
3732
3744
|
// empty
|
|
3733
3745
|
},
|
|
3734
|
-
}, children: item.subComponent && (jsxRuntime.jsx("div", { className:
|
|
3746
|
+
}, children: item.subComponent && (jsxRuntime.jsx("div", { className: 'subComponent', children: jsxRuntime.jsx(item.subComponent, {}) })) })) }, `${String(item.label)}_subcomponent`))] }, `menu-wrapper-${index}`)] }, `${index}`)));
|
|
3735
3747
|
})] }) })] }));
|
|
3736
3748
|
};
|
|
3737
3749
|
|
|
@@ -3739,45 +3751,45 @@ var css_248z$1 = ".LuiTextInput.GridLuiTextInput{margin-bottom:0}.LuiTextInput-f
|
|
|
3739
3751
|
styleInject(css_248z$1);
|
|
3740
3752
|
|
|
3741
3753
|
const TextInputFormatted = (props) => {
|
|
3742
|
-
return (jsxRuntime.jsxs("div", { className: clsx(
|
|
3754
|
+
return (jsxRuntime.jsxs("div", { className: clsx('LuiTextInput GridLuiTextInput Grid-popoverContainer', props.error && 'hasError', props.className), children: [jsxRuntime.jsxs("span", { className: "LuiTextInput-inputWrapper", children: [jsxRuntime.jsx("input", { type: 'text', spellCheck: true, defaultValue: props.value, ...lodashEs.omit(props, ['error', 'value', 'helpText', 'formatted', 'className', 'allowTabToSave']), className: 'LuiTextInput-input', onMouseEnter: (e) => {
|
|
3743
3755
|
e.currentTarget.focus();
|
|
3744
3756
|
props.onMouseEnter && props.onMouseEnter(e);
|
|
3745
|
-
}, "data-allowtabtosave": props.allowTabToSave }), jsxRuntime.jsx("span", { className:
|
|
3757
|
+
}, "data-allowtabtosave": props.allowTabToSave }), jsxRuntime.jsx("span", { className: 'LuiTextInput-formatted', children: props.formatted })] }), jsxRuntime.jsx(FormError, { error: props.error, helpText: props.helpText })] }));
|
|
3746
3758
|
};
|
|
3747
3759
|
|
|
3748
3760
|
const bearingValueFormatter = (value) => {
|
|
3749
|
-
const safeValue = typeof value
|
|
3761
|
+
const safeValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
3750
3762
|
if (safeValue == null) {
|
|
3751
|
-
return
|
|
3763
|
+
return '–';
|
|
3752
3764
|
}
|
|
3753
3765
|
return convertDDToDMS(safeValue, false);
|
|
3754
3766
|
};
|
|
3755
3767
|
const bearingCorrectionValueFormatter = (value) => {
|
|
3756
3768
|
const safeValue = value;
|
|
3757
3769
|
if (safeValue == null) {
|
|
3758
|
-
return
|
|
3770
|
+
return '–';
|
|
3759
3771
|
}
|
|
3760
|
-
if (typeof safeValue ===
|
|
3772
|
+
if (typeof safeValue === 'string') {
|
|
3761
3773
|
return convertDDToDMS(bearingNumberParser(safeValue), true, 4);
|
|
3762
3774
|
}
|
|
3763
3775
|
return convertDDToDMS(safeValue, true, 4);
|
|
3764
3776
|
};
|
|
3765
3777
|
const bearingNumberParser = (value) => {
|
|
3766
|
-
if (value ===
|
|
3778
|
+
if (value === '')
|
|
3767
3779
|
return null;
|
|
3768
3780
|
return parseFloat(value);
|
|
3769
3781
|
};
|
|
3770
3782
|
const validMaskForDmsBearing = /^((-)?\d+)?(\.([0-5](\d([0-5](\d(\d+)?)?)?)?)?)?$/;
|
|
3771
3783
|
const bearingStringValidator = (value, customInvalid) => {
|
|
3772
3784
|
value = value.trim();
|
|
3773
|
-
if (value ===
|
|
3785
|
+
if (value === '')
|
|
3774
3786
|
return null;
|
|
3775
3787
|
const match = value.match(validMaskForDmsBearing);
|
|
3776
3788
|
if (!match)
|
|
3777
|
-
return
|
|
3789
|
+
return 'Bearing must be a number in D.MMSSS format';
|
|
3778
3790
|
const decimalPart = match[4];
|
|
3779
3791
|
if (decimalPart != null && decimalPart.length > 5) {
|
|
3780
|
-
return
|
|
3792
|
+
return 'Bearing has a maximum of 5 decimal places';
|
|
3781
3793
|
}
|
|
3782
3794
|
const bearing = parseFloat(value);
|
|
3783
3795
|
return customInvalid ? customInvalid(bearing) : null;
|
|
@@ -3796,9 +3808,9 @@ const bearingStringValidator = (value, customInvalid) => {
|
|
|
3796
3808
|
*/
|
|
3797
3809
|
const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
|
|
3798
3810
|
if (dd == null)
|
|
3799
|
-
return
|
|
3811
|
+
return '–';
|
|
3800
3812
|
// toFixed rounds parts up greater than 60, which has to be corrected below
|
|
3801
|
-
const [bearingWholeString, bearingDecimalString] = dd.toFixed(5).split(
|
|
3813
|
+
const [bearingWholeString, bearingDecimalString] = dd.toFixed(5).split('.');
|
|
3802
3814
|
let bearingWhole = Math.abs(parseInt(bearingWholeString));
|
|
3803
3815
|
let minNumeric = parseInt(bearingDecimalString?.substring(0, 2));
|
|
3804
3816
|
let secNumeric = parseInt(bearingDecimalString?.substring(2, 4));
|
|
@@ -3814,11 +3826,11 @@ const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
|
|
|
3814
3826
|
if (bearingWhole >= 360) {
|
|
3815
3827
|
bearingWhole -= 360;
|
|
3816
3828
|
}
|
|
3817
|
-
const minString = minNumeric.toString().padStart(2,
|
|
3818
|
-
const secString = secNumeric.toString().padStart(2,
|
|
3829
|
+
const minString = minNumeric.toString().padStart(2, '0');
|
|
3830
|
+
const secString = secNumeric.toString().padStart(2, '0');
|
|
3819
3831
|
const deciSecString = bearingDecimalString?.substring(4, 5);
|
|
3820
|
-
let dmsString = `${showPositiveSymbol && dd > 0 ?
|
|
3821
|
-
if (trailingZeroDp === 5 || deciSecString !=
|
|
3832
|
+
let dmsString = `${showPositiveSymbol && dd > 0 ? '+' : ''}${dd < 0 ? '-' : ''}${bearingWhole}°`;
|
|
3833
|
+
if (trailingZeroDp === 5 || deciSecString != '0') {
|
|
3822
3834
|
dmsString += `\xa0${minString}'\xa0${secString}.${deciSecString}"`; // "\xa0" is here for non-breaking space
|
|
3823
3835
|
}
|
|
3824
3836
|
else if (trailingZeroDp === 4 || secNumeric != 0) {
|
|
@@ -3831,27 +3843,27 @@ const convertDDToDMS = (dd, showPositiveSymbol = true, trailingZeroDp = 2) => {
|
|
|
3831
3843
|
};
|
|
3832
3844
|
const bearingRangeValidator = (value) => {
|
|
3833
3845
|
if (value === null)
|
|
3834
|
-
return
|
|
3846
|
+
return 'Bearing is required';
|
|
3835
3847
|
if (value >= 360)
|
|
3836
|
-
return
|
|
3848
|
+
return 'Bearing must be less than 360 degrees';
|
|
3837
3849
|
if (value < 0)
|
|
3838
|
-
return
|
|
3850
|
+
return 'Bearing must not be negative';
|
|
3839
3851
|
return null;
|
|
3840
3852
|
};
|
|
3841
3853
|
const bearingCorrectionRangeValidator = (value) => {
|
|
3842
3854
|
if (value === null)
|
|
3843
|
-
return
|
|
3855
|
+
return 'Bearing correction is required';
|
|
3844
3856
|
if (value >= 360)
|
|
3845
|
-
return
|
|
3857
|
+
return 'Bearing correction must be less than 360 degrees';
|
|
3846
3858
|
if (value <= -180)
|
|
3847
|
-
return
|
|
3859
|
+
return 'Bearing correction must be greater then -180 degrees';
|
|
3848
3860
|
return null;
|
|
3849
3861
|
};
|
|
3850
3862
|
|
|
3851
3863
|
const GridFormEditBearing = (props) => {
|
|
3852
3864
|
const { field, value: initialValue } = useGridPopoverContext();
|
|
3853
3865
|
// This clears out any scientific precision
|
|
3854
|
-
const defaultValue = React.useMemo(() => (initialValue == null ?
|
|
3866
|
+
const defaultValue = React.useMemo(() => (initialValue == null ? '' : parseFloat(parseFloat(initialValue).toFixed(10)).toString()), [initialValue]);
|
|
3855
3867
|
const [value, setValue] = React.useState(defaultValue);
|
|
3856
3868
|
const invalid = React.useCallback(() => bearingStringValidator(value, props.range), [props.range, value]);
|
|
3857
3869
|
const save = React.useCallback(async (selectedRows) => {
|
|
@@ -3865,7 +3877,7 @@ const GridFormEditBearing = (props) => {
|
|
|
3865
3877
|
}
|
|
3866
3878
|
else {
|
|
3867
3879
|
if (field == null) {
|
|
3868
|
-
console.error(
|
|
3880
|
+
console.error('field is not defined in ColDef');
|
|
3869
3881
|
}
|
|
3870
3882
|
else {
|
|
3871
3883
|
selectedRows.forEach((row) => {
|
|
@@ -3880,11 +3892,11 @@ const GridFormEditBearing = (props) => {
|
|
|
3880
3892
|
invalid,
|
|
3881
3893
|
save,
|
|
3882
3894
|
});
|
|
3883
|
-
return popoverWrapper(jsxRuntime.jsx("div", { className:
|
|
3895
|
+
return popoverWrapper(jsxRuntime.jsx("div", { className: 'GridFormEditBearing-input', children: jsxRuntime.jsx(TextInputFormatted, { value: defaultValue, onChange: (e) => {
|
|
3884
3896
|
setValue(e.target.value.trim());
|
|
3885
3897
|
}, autoFocus: true, placeholder: props.placeHolder, formatted: bearingStringValidator(value, props.range) || !props.formatValue
|
|
3886
|
-
?
|
|
3887
|
-
: props.formatValue(bearingNumberParser(value)), error: bearingStringValidator(value, props.range), helpText:
|
|
3898
|
+
? '?'
|
|
3899
|
+
: props.formatValue(bearingNumberParser(value)), error: bearingStringValidator(value, props.range), helpText: 'Press enter or tab to save' }) }));
|
|
3888
3900
|
};
|
|
3889
3901
|
|
|
3890
3902
|
const GridFormMessage = (props) => {
|
|
@@ -3892,11 +3904,11 @@ const GridFormMessage = (props) => {
|
|
|
3892
3904
|
const [message, setMessage] = React.useState(null);
|
|
3893
3905
|
const { popoverWrapper } = useGridPopoverHook({ className: props.className });
|
|
3894
3906
|
React.useEffect(() => {
|
|
3895
|
-
(async () => {
|
|
3907
|
+
void (async () => {
|
|
3896
3908
|
setMessage(await props.message(selectedRows));
|
|
3897
|
-
})()
|
|
3909
|
+
})();
|
|
3898
3910
|
}, [props, selectedRows]);
|
|
3899
|
-
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: message === null, className: clsx(
|
|
3911
|
+
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: message === null, className: clsx('GridFormMessage-container', props.className), children: jsxRuntime.jsx(jsxRuntime.Fragment, { children: message }) }));
|
|
3900
3912
|
};
|
|
3901
3913
|
|
|
3902
3914
|
const GridFormMultiSelect = (props) => {
|
|
@@ -3904,8 +3916,8 @@ const GridFormMultiSelect = (props) => {
|
|
|
3904
3916
|
const subComponentIsValidRef = React.useRef({});
|
|
3905
3917
|
const optionsInitialising = React.useRef(false);
|
|
3906
3918
|
const firstInputSubComponent = React.useRef(null);
|
|
3907
|
-
const [filter, setFilter] = React.useState(
|
|
3908
|
-
const [initialValues, setInitialValues] = React.useState(
|
|
3919
|
+
const [filter, setFilter] = React.useState('');
|
|
3920
|
+
const [initialValues, setInitialValues] = React.useState('');
|
|
3909
3921
|
const [options, setOptions] = React.useState();
|
|
3910
3922
|
const invalid = React.useCallback(() => {
|
|
3911
3923
|
if (!options)
|
|
@@ -3933,8 +3945,8 @@ const GridFormMultiSelect = (props) => {
|
|
|
3933
3945
|
if (options || optionsInitialising.current)
|
|
3934
3946
|
return;
|
|
3935
3947
|
optionsInitialising.current = true;
|
|
3936
|
-
(async () => {
|
|
3937
|
-
const optionsList = typeof props.options ===
|
|
3948
|
+
void (async () => {
|
|
3949
|
+
const optionsList = typeof props.options === 'function' ? await props.options(selectedRows) : props.options;
|
|
3938
3950
|
setInitialValues(JSON.stringify(optionsList));
|
|
3939
3951
|
setOptions(optionsList);
|
|
3940
3952
|
optionsInitialising.current = false;
|
|
@@ -3946,7 +3958,7 @@ const GridFormMultiSelect = (props) => {
|
|
|
3946
3958
|
const headerGroups = React.useMemo(() => {
|
|
3947
3959
|
if (!options)
|
|
3948
3960
|
return undefined;
|
|
3949
|
-
const result = lodashEs.groupBy(options.filter((o) => textMatch(o.label, filter) && o.value != null),
|
|
3961
|
+
const result = lodashEs.groupBy(options.filter((o) => textMatch(o.label, filter) && o.value != null), 'filter');
|
|
3950
3962
|
// remove leading/trailing/duplicate dividers
|
|
3951
3963
|
return lodashEs.fromPairs(lodashEs.toPairs(result).map(([key, arr]) => {
|
|
3952
3964
|
let lastWasDivider = true;
|
|
@@ -3970,14 +3982,14 @@ const GridFormMultiSelect = (props) => {
|
|
|
3970
3982
|
];
|
|
3971
3983
|
}));
|
|
3972
3984
|
}, [filter, options]);
|
|
3973
|
-
const headers = React.useMemo(() => props.headers ?? [{ header:
|
|
3985
|
+
const headers = React.useMemo(() => props.headers ?? [{ header: '' }], [props.headers]);
|
|
3974
3986
|
const { popoverWrapper, triggerSave } = useGridPopoverHook({
|
|
3975
3987
|
className: props.className,
|
|
3976
3988
|
invalid,
|
|
3977
3989
|
save,
|
|
3978
3990
|
});
|
|
3979
|
-
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className:
|
|
3980
|
-
(lodashEs.isEmpty(headerGroups) || !lodashEs.toPairs(headerGroups).some(([_, options]) => !lodashEs.isEmpty(options))) && (jsxRuntime.jsx(MenuItem, { className:
|
|
3991
|
+
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormMultiSelect-container', children: options && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [props.filtered && (jsxRuntime.jsx(FilterInput, { headerGroups, options, setOptions, filter, setFilter, triggerSave, filterHelpText: props.filterHelpText, onSelectFilter: props.onSelectFilter, filterPlaceholder: props.filterPlaceholder })), headerGroups &&
|
|
3992
|
+
(lodashEs.isEmpty(headerGroups) || !lodashEs.toPairs(headerGroups).some(([_, options]) => !lodashEs.isEmpty(options))) && (jsxRuntime.jsx(MenuItem, { className: 'GridMultiSelect-noOptions', disabled: true, children: props.noOptionsMessage ?? 'No Options' }, 'noOptions')), headerGroups && !lodashEs.isEmpty(headerGroups) && (jsxRuntime.jsx("div", { className: 'GridFormMultiSelect-options', children: headers.map((header, index) => {
|
|
3981
3993
|
const subOptions = headerGroups[`${header.filter}`];
|
|
3982
3994
|
return (!lodashEs.isEmpty(subOptions) && (jsxRuntime.jsxs(React.Fragment, { children: [header.header && jsxRuntime.jsx(MenuHeader, { children: header.header }), subOptions.map((item, index) => item.value === MenuSeparatorString ? (jsxRuntime.jsx(MenuDivider, {}, `div_${index}`)) : (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(MenuRadioItem, { item: item, options: options, setOptions: setOptions, onChecked: () => {
|
|
3983
3995
|
// Default to focus on first input in subComponent
|
|
@@ -4019,7 +4031,7 @@ const FilterInput = (props) => {
|
|
|
4019
4031
|
return;
|
|
4020
4032
|
const filterTrimmed = filter.trim();
|
|
4021
4033
|
if (lodashEs.isEmpty(filterTrimmed)) {
|
|
4022
|
-
triggerSave()
|
|
4034
|
+
void triggerSave();
|
|
4023
4035
|
return;
|
|
4024
4036
|
}
|
|
4025
4037
|
const preFilterOptions = JSON.stringify(options);
|
|
@@ -4028,15 +4040,15 @@ const FilterInput = (props) => {
|
|
|
4028
4040
|
if (preFilterOptions === JSON.stringify(options))
|
|
4029
4041
|
return;
|
|
4030
4042
|
setOptions([...options]);
|
|
4031
|
-
setFilter(
|
|
4043
|
+
setFilter('');
|
|
4032
4044
|
}, [filter, onSelectFilter, options, setFilter, setOptions, triggerSave]);
|
|
4033
4045
|
const handleKeyDown = React.useCallback((e) => {
|
|
4034
|
-
if (e.key ===
|
|
4046
|
+
if (e.key === 'Enter') {
|
|
4035
4047
|
enterHasBeenPressed.current = true;
|
|
4036
4048
|
}
|
|
4037
4049
|
}, []);
|
|
4038
4050
|
const handleKeyUp = React.useCallback((e) => {
|
|
4039
|
-
if (e.key ===
|
|
4051
|
+
if (e.key === 'Enter') {
|
|
4040
4052
|
e.stopPropagation();
|
|
4041
4053
|
e.preventDefault();
|
|
4042
4054
|
if (e.ctrlKey)
|
|
@@ -4044,22 +4056,22 @@ const FilterInput = (props) => {
|
|
|
4044
4056
|
else if (enterHasBeenPressed.current) {
|
|
4045
4057
|
const filterTrimmed = filter.trim();
|
|
4046
4058
|
if (lodashEs.isEmpty(filterTrimmed)) {
|
|
4047
|
-
triggerSave()
|
|
4059
|
+
void triggerSave();
|
|
4048
4060
|
return;
|
|
4049
4061
|
}
|
|
4050
4062
|
onSelectFilter && addCustomFilterValue();
|
|
4051
4063
|
}
|
|
4052
4064
|
lastKeyWasEnter.current = true;
|
|
4053
4065
|
}
|
|
4054
|
-
else if (e.key ===
|
|
4055
|
-
lastKeyWasEnter.current && setFilter(
|
|
4066
|
+
else if (e.key === 'Control') {
|
|
4067
|
+
lastKeyWasEnter.current && setFilter('');
|
|
4056
4068
|
lastKeyWasEnter.current = false;
|
|
4057
4069
|
}
|
|
4058
4070
|
else {
|
|
4059
4071
|
lastKeyWasEnter.current = false;
|
|
4060
4072
|
}
|
|
4061
4073
|
}, [addCustomFilterValue, filter, onSelectFilter, setFilter, toggleSelectAllVisible, triggerSave]);
|
|
4062
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(FocusableItem, { className:
|
|
4074
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(FocusableItem, { className: 'filter-item', children: (_) => (jsxRuntime.jsxs("div", { style: { width: '100%' }, className: 'GridFormMultiSelect-filter', children: [jsxRuntime.jsx("input", { className: 'LuiTextInput-input', type: "text", placeholder: filterPlaceholder ?? 'Filter...', "data-testid": 'filteredMenu-free-text-input', value: filter, "data-disableenterautosave": true, "data-allowtabtosave": true, onChange: (e) => setFilter(e.target.value), onKeyDown: handleKeyDown, onKeyUp: handleKeyUp }), filterHelpText && (jsxRuntime.jsx(FormError, { error: null, helpText: typeof filterHelpText === 'function' ? filterHelpText(filter.trim(), options) : filterHelpText }))] })) }, 'filter'), jsxRuntime.jsx(MenuDivider, {}, `$$divider_filter`)] }));
|
|
4063
4075
|
};
|
|
4064
4076
|
const MenuRadioItem = (props) => {
|
|
4065
4077
|
const { item, options, setOptions } = props;
|
|
@@ -4069,12 +4081,12 @@ const MenuRadioItem = (props) => {
|
|
|
4069
4081
|
}, [options, setOptions]);
|
|
4070
4082
|
return (jsxRuntime.jsx(MenuItem, { onClick: (e) => {
|
|
4071
4083
|
// Global react-menu MenuItem handler handles tabs
|
|
4072
|
-
if (e.key !==
|
|
4084
|
+
if (e.key !== 'Tab' && e.key !== 'Enter') {
|
|
4073
4085
|
e.keepOpen = true;
|
|
4074
4086
|
toggleValue(item);
|
|
4075
4087
|
}
|
|
4076
4088
|
item.checked && props.onChecked && props.onChecked();
|
|
4077
|
-
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: item.checked ?? false, value: `${item.value}`, label: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.warning && jsxRuntime.jsx(GridIcon, { icon:
|
|
4089
|
+
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: item.checked ?? false, value: `${item.value}`, label: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [item.warning && jsxRuntime.jsx(GridIcon, { icon: 'ic_warning_outline', title: item.warning }), item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)] }), inputProps: {
|
|
4078
4090
|
onClick: (e) => {
|
|
4079
4091
|
// Click is handled by MenuItem onClick
|
|
4080
4092
|
e.preventDefault();
|
|
@@ -4090,8 +4102,8 @@ function MenuSubComponentFr(props, ref) {
|
|
|
4090
4102
|
const focusableRef = React.useRef(null);
|
|
4091
4103
|
React.useEffect(() => {
|
|
4092
4104
|
if (focusableRef.current) {
|
|
4093
|
-
const firstInputElement = focusableRef.current.querySelectorAll(
|
|
4094
|
-
if (typeof ref ===
|
|
4105
|
+
const firstInputElement = focusableRef.current.querySelectorAll('input')[0] ?? null;
|
|
4106
|
+
if (typeof ref === 'function') {
|
|
4095
4107
|
ref(firstInputElement);
|
|
4096
4108
|
}
|
|
4097
4109
|
else if (ref) {
|
|
@@ -4099,7 +4111,7 @@ function MenuSubComponentFr(props, ref) {
|
|
|
4099
4111
|
}
|
|
4100
4112
|
}
|
|
4101
4113
|
}, [ref]);
|
|
4102
|
-
return (jsxRuntime.jsx(FocusableItem, { className:
|
|
4114
|
+
return (jsxRuntime.jsx(FocusableItem, { className: 'LuiDeprecatedForms', ref: focusableRef, children: () => (jsxRuntime.jsx(GridSubComponentContext.Provider, { value: {
|
|
4103
4115
|
context: { options },
|
|
4104
4116
|
data,
|
|
4105
4117
|
value: item.subValue,
|
|
@@ -4111,7 +4123,7 @@ function MenuSubComponentFr(props, ref) {
|
|
|
4111
4123
|
subComponentIsValid[`${item.value}`] = valid;
|
|
4112
4124
|
},
|
|
4113
4125
|
triggerSave,
|
|
4114
|
-
}, children: jsxRuntime.jsx("div", { className:
|
|
4126
|
+
}, children: jsxRuntime.jsx("div", { className: 'subComponent', children: item.subComponent && jsxRuntime.jsx(item.subComponent, {}) }) })) }, `${item.value}_subcomponent`));
|
|
4115
4127
|
}
|
|
4116
4128
|
|
|
4117
4129
|
const GridFormMultiSelectGrid = (props) => {
|
|
@@ -4156,33 +4168,33 @@ const GridFormMultiSelectGrid = (props) => {
|
|
|
4156
4168
|
if (options || optionsInitialising.current)
|
|
4157
4169
|
return;
|
|
4158
4170
|
optionsInitialising.current = true;
|
|
4159
|
-
(async () => {
|
|
4160
|
-
const optionsList = typeof props.options ===
|
|
4161
|
-
setInitialValues(optionsList.map((o) => ({ ...o, label:
|
|
4171
|
+
void (async () => {
|
|
4172
|
+
const optionsList = typeof props.options === 'function' ? await props.options(selectedRows) : props.options;
|
|
4173
|
+
setInitialValues(optionsList.map((o) => ({ ...o, label: '' })));
|
|
4162
4174
|
setOptions(optionsList);
|
|
4163
4175
|
optionsInitialising.current = false;
|
|
4164
4176
|
})();
|
|
4165
4177
|
}, [options, props, selectedRows]);
|
|
4166
4178
|
const toggleValue = React.useCallback((item) => {
|
|
4167
4179
|
if (options) {
|
|
4168
|
-
item.checked = item.checked === true && item.canSelectPartial ?
|
|
4180
|
+
item.checked = item.checked === true && item.canSelectPartial ? 'partial' : !item.checked;
|
|
4169
4181
|
setOptions([...options]);
|
|
4170
4182
|
}
|
|
4171
4183
|
}, [options, setOptions]);
|
|
4172
|
-
return popoverWrapper(jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx("div", { className:
|
|
4173
|
-
display:
|
|
4174
|
-
gridAutoFlow:
|
|
4184
|
+
return popoverWrapper(jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx("div", { className: 'Grid-popoverContainer', children: jsxRuntime.jsx("div", { style: {
|
|
4185
|
+
display: 'grid',
|
|
4186
|
+
gridAutoFlow: 'column',
|
|
4175
4187
|
gridTemplateRows: `repeat(${props.maxRowCount ?? 10}, auto)`,
|
|
4176
|
-
maxWidth:
|
|
4177
|
-
overflowX:
|
|
4188
|
+
maxWidth: 'calc(min(100vw,500px))',
|
|
4189
|
+
overflowX: 'auto',
|
|
4178
4190
|
}, children: options &&
|
|
4179
4191
|
options.map((o) => (jsxRuntime.jsx(jsxRuntime.Fragment, { children: jsxRuntime.jsx(MenuItem, { onClick: (e) => {
|
|
4180
4192
|
// Global react-menu MenuItem handler handles tabs
|
|
4181
|
-
if (e.key !==
|
|
4193
|
+
if (e.key !== 'Tab' && e.key !== 'Enter') {
|
|
4182
4194
|
e.keepOpen = true;
|
|
4183
4195
|
toggleValue(o);
|
|
4184
4196
|
}
|
|
4185
|
-
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: !!o.checked, isIndeterminate: o.checked ===
|
|
4197
|
+
}, children: jsxRuntime.jsx(lui.LuiCheckboxInput, { isChecked: !!o.checked, isIndeterminate: o.checked === 'partial', value: `${o.value}`, label: jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [o.warning && jsxRuntime.jsx(GridIcon, { icon: 'ic_warning_outline', title: o.warning }, '$$icon$$'), jsxRuntime.jsx("span", { className: 'GridMultiSelectGrid-Label', children: o.label ?? (o.value == null ? `<${o.value}>` : `${o.value}`) }, '$$label$$')] }), inputProps: {
|
|
4186
4198
|
onClick: (e) => {
|
|
4187
4199
|
// Click is handled by MenuItem onClick
|
|
4188
4200
|
e.preventDefault();
|
|
@@ -4194,7 +4206,7 @@ const GridFormMultiSelectGrid = (props) => {
|
|
|
4194
4206
|
};
|
|
4195
4207
|
|
|
4196
4208
|
/** Menu configuration types **/
|
|
4197
|
-
const __isMenuSeparator__ =
|
|
4209
|
+
const __isMenuSeparator__ = '__isMenuSeparator__';
|
|
4198
4210
|
const PopoutMenuSeparator = Object.freeze({ label: __isMenuSeparator__ });
|
|
4199
4211
|
/**
|
|
4200
4212
|
* NOTE: If the popout menu doesn't appear on single click when also selecting row it's because
|
|
@@ -4211,7 +4223,7 @@ const GridFormPopoverMenu = (props) => {
|
|
|
4211
4223
|
if (props.defaultAction)
|
|
4212
4224
|
await props.defaultAction(params);
|
|
4213
4225
|
else
|
|
4214
|
-
console.error(`No action specified for ${params.menuOption.label} menu options`);
|
|
4226
|
+
console.error(`No action specified for ${String(params.menuOption.label)} menu options`);
|
|
4215
4227
|
}, [props]);
|
|
4216
4228
|
// Load up options list if it's async function
|
|
4217
4229
|
React.useEffect(() => {
|
|
@@ -4219,8 +4231,8 @@ const GridFormPopoverMenu = (props) => {
|
|
|
4219
4231
|
return;
|
|
4220
4232
|
optionsInitialising.current = true;
|
|
4221
4233
|
const optionsConf = props.options ?? [];
|
|
4222
|
-
(async () => {
|
|
4223
|
-
const newOptions = typeof optionsConf
|
|
4234
|
+
void (async () => {
|
|
4235
|
+
const newOptions = typeof optionsConf === 'function' ? await optionsConf(selectedRows) : optionsConf;
|
|
4224
4236
|
setOptions(newOptions);
|
|
4225
4237
|
if (!props.defaultAction) {
|
|
4226
4238
|
const anyOptionsAreMissingAction = newOptions.some((option) => !option.action);
|
|
@@ -4250,7 +4262,7 @@ const GridFormPopoverMenu = (props) => {
|
|
|
4250
4262
|
else {
|
|
4251
4263
|
subComponentIsValid.current = true;
|
|
4252
4264
|
setSubSelectedValue(null);
|
|
4253
|
-
await updateValue(async () => actionClick(item), e.key ===
|
|
4265
|
+
await updateValue(async () => actionClick(item), e.key === 'Tab' ? (e.shiftKey ? -1 : 1) : 0);
|
|
4254
4266
|
}
|
|
4255
4267
|
}, [actionClick, subComponentSelected, updateValue]);
|
|
4256
4268
|
const save = React.useCallback(async () => {
|
|
@@ -4268,7 +4280,7 @@ const GridFormPopoverMenu = (props) => {
|
|
|
4268
4280
|
invalid: () => subComponentSelected && !subComponentIsValid.current,
|
|
4269
4281
|
save,
|
|
4270
4282
|
});
|
|
4271
|
-
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className:
|
|
4283
|
+
return popoverWrapper(jsxRuntime.jsx(ComponentLoadingWrapper, { loading: !options, className: 'GridFormPopupMenu', children: jsxRuntime.jsx(jsxRuntime.Fragment, { children: lodashEs.isEmpty(options) ? (jsxRuntime.jsx(MenuItem, { className: 'GridPopoverMenu-noOptions', disabled: true, children: "No actions" }, `GridPopoverMenu-empty`)) : (options?.map((item, index) => item.label === '__isMenuSeparator__' ? (jsxRuntime.jsx(MenuDivider, {}, `$$divider_${index}`)) : (!item.hidden && (jsxRuntime.jsxs(React.Fragment, { children: [item.subMenu ? (jsxRuntime.jsx(SubMenu, { disabled: !!item.disabled, label: item.label, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', children: jsxRuntime.jsx(item.subMenu, {}) }, `${String(item.label)}`)) : (jsxRuntime.jsx(MenuItem, { onClick: (e) => void onMenuItemClick(e, item), disabled: !!item.disabled, title: item.disabled && typeof item.disabled !== 'boolean' ? item.disabled : '', children: item.label }, `${String(item.label)}`)), item.subComponent && subComponentSelected === item && (jsxRuntime.jsx(FocusableItem, { className: 'LuiDeprecatedForms', children: () => (jsxRuntime.jsx(GridSubComponentContext.Provider, { value: {
|
|
4272
4284
|
context: {},
|
|
4273
4285
|
data,
|
|
4274
4286
|
value: subSelectedValue,
|
|
@@ -4279,13 +4291,13 @@ const GridFormPopoverMenu = (props) => {
|
|
|
4279
4291
|
subComponentIsValid.current = valid;
|
|
4280
4292
|
},
|
|
4281
4293
|
triggerSave,
|
|
4282
|
-
}, children: jsxRuntime.jsx("div", { className:
|
|
4294
|
+
}, children: jsxRuntime.jsx("div", { className: 'subComponent', children: item.subComponent && jsxRuntime.jsx(item.subComponent, {}) }) })) }, `${String(item.label)}_subcomponent`))] }, `${String(item.label)}`))))) }) }));
|
|
4283
4295
|
};
|
|
4284
4296
|
|
|
4285
4297
|
const TextAreaInput = (props) => {
|
|
4286
4298
|
const reactId = React.useId();
|
|
4287
4299
|
const id = props?.id ?? reactId;
|
|
4288
|
-
return (jsxRuntime.jsxs("div", { className: clsx(
|
|
4300
|
+
return (jsxRuntime.jsxs("div", { className: clsx('LuiTextAreaInput Grid-popoverContainer', props.disabled ? 'isDisabled' : '', props.error ? 'hasError' : '', props.className), children: [jsxRuntime.jsxs("label", { htmlFor: id, children: [props.mandatory != null && jsxRuntime.jsx("span", { className: "LuiTextAreaInput-mandatory", children: "*" }), props.label != null && jsxRuntime.jsx("span", { className: "LuiTextAreaInput-label", children: props.label }), jsxRuntime.jsx("div", { className: "LuiTextAreaInput-wrapper", children: jsxRuntime.jsx("textarea", { rows: 5, ...lodashEs.omit(props, ['error', 'value', 'helpText', 'formatted', 'className', 'allowTabToSave']), id: id, value: props.value ?? '', spellCheck: true, onMouseEnter: (e) => {
|
|
4289
4301
|
if (document.activeElement != e.currentTarget) {
|
|
4290
4302
|
e.currentTarget.focus();
|
|
4291
4303
|
e.currentTarget.selectionStart = e.currentTarget.value.length;
|
|
@@ -4298,11 +4310,11 @@ const TextInputValidator = (props, value, data, context) => {
|
|
|
4298
4310
|
if (value == null)
|
|
4299
4311
|
return null;
|
|
4300
4312
|
// This can happen because subcomponent is invoked without type safety
|
|
4301
|
-
if (typeof value !==
|
|
4302
|
-
return
|
|
4313
|
+
if (typeof value !== 'string') {
|
|
4314
|
+
return 'Value is not a string';
|
|
4303
4315
|
}
|
|
4304
|
-
if (props.required && value.trim() ==
|
|
4305
|
-
return
|
|
4316
|
+
if (props.required && value.trim() == '') {
|
|
4317
|
+
return 'Must not be empty';
|
|
4306
4318
|
}
|
|
4307
4319
|
if (props.maxLength && value.length > props.maxLength) {
|
|
4308
4320
|
return `Must be no longer than ${props.maxLength} characters`;
|
|
@@ -4312,10 +4324,10 @@ const TextInputValidator = (props, value, data, context) => {
|
|
|
4312
4324
|
}
|
|
4313
4325
|
const nf = props.numberFormat;
|
|
4314
4326
|
if (nf) {
|
|
4315
|
-
if (value !=
|
|
4327
|
+
if (value != '' && !isFloat(value)) {
|
|
4316
4328
|
return `Must be a valid number`;
|
|
4317
4329
|
}
|
|
4318
|
-
if (value !=
|
|
4330
|
+
if (value != '') {
|
|
4319
4331
|
const number = parseFloat(value);
|
|
4320
4332
|
if (nf.notZero && number === 0) {
|
|
4321
4333
|
return `Must not be 0`;
|
|
@@ -4332,12 +4344,12 @@ const TextInputValidator = (props, value, data, context) => {
|
|
|
4332
4344
|
if (nf.leMax != null && number > nf.leMax) {
|
|
4333
4345
|
return `Must not be greater than ${nf.leMax.toLocaleString()}`;
|
|
4334
4346
|
}
|
|
4335
|
-
if (nf.precision != null && value !=
|
|
4347
|
+
if (nf.precision != null && value != '') {
|
|
4336
4348
|
if (parseFloat(number.toPrecision(nf.precision)) != number) {
|
|
4337
4349
|
return `Must have no more than ${nf.precision} digits precision`;
|
|
4338
4350
|
}
|
|
4339
4351
|
}
|
|
4340
|
-
if (nf.scale != null && value !=
|
|
4352
|
+
if (nf.scale != null && value != '') {
|
|
4341
4353
|
if (parseFloat(number.toFixed(nf.scale)) != number) {
|
|
4342
4354
|
return nf.scale == 0 ? `Must be a whole number` : `Must have no more than ${nf.scale} decimal places`;
|
|
4343
4355
|
}
|
|
@@ -4352,7 +4364,7 @@ const TextInputValidator = (props, value, data, context) => {
|
|
|
4352
4364
|
|
|
4353
4365
|
const GridFormSubComponentTextArea = (props) => {
|
|
4354
4366
|
const { value, data, setValue, setValid, context } = React.useContext(GridSubComponentContext);
|
|
4355
|
-
const helpText = props.helpText ??
|
|
4367
|
+
const helpText = props.helpText ?? 'Press tab to save';
|
|
4356
4368
|
// If is not initialised yet as it's just been created then set the default value
|
|
4357
4369
|
React.useEffect(() => {
|
|
4358
4370
|
if (value == null)
|
|
@@ -4362,12 +4374,12 @@ const GridFormSubComponentTextArea = (props) => {
|
|
|
4362
4374
|
React.useEffect(() => {
|
|
4363
4375
|
setValid(value != null && invalid() == null);
|
|
4364
4376
|
}, [setValid, invalid, value]);
|
|
4365
|
-
return (jsxRuntime.jsx("div", { className: clsx(
|
|
4377
|
+
return (jsxRuntime.jsx("div", { className: clsx('FreeTextInput', props.className), children: jsxRuntime.jsx(TextAreaInput, { className: 'free-text-input', value: value, onChange: (e) => setValue(e.target.value), error: invalid(), helpText: helpText, placeholder: props.placeholder, allowTabToSave: true }) }));
|
|
4366
4378
|
};
|
|
4367
4379
|
|
|
4368
4380
|
const GridFormSubComponentTextInput = (props) => {
|
|
4369
4381
|
const { value, setValue, setValid, data, context } = React.useContext(GridSubComponentContext);
|
|
4370
|
-
const helpText = props.helpText ??
|
|
4382
|
+
const helpText = props.helpText ?? 'Press enter or tab to save';
|
|
4371
4383
|
// If is not initialised yet as it's just been created then set the default value
|
|
4372
4384
|
React.useEffect(() => {
|
|
4373
4385
|
if (value == null)
|
|
@@ -4377,14 +4389,14 @@ const GridFormSubComponentTextInput = (props) => {
|
|
|
4377
4389
|
React.useEffect(() => {
|
|
4378
4390
|
setValid(value != null && invalid() == null);
|
|
4379
4391
|
}, [setValid, invalid, value]);
|
|
4380
|
-
return (jsxRuntime.jsx(TextInputFormatted, { value: value, error: invalid(), onChange: (e) => setValue(e.target.value), helpText: helpText, placeholder: props.placeholder, style: { width:
|
|
4392
|
+
return (jsxRuntime.jsx(TextInputFormatted, { value: value, error: invalid(), onChange: (e) => setValue(e.target.value), helpText: helpText, placeholder: props.placeholder, style: { width: '100%' }, allowTabToSave: true }));
|
|
4381
4393
|
};
|
|
4382
4394
|
|
|
4383
4395
|
const GridFormTextArea = (props) => {
|
|
4384
4396
|
const { field, value: initialVale, data } = useGridPopoverContext();
|
|
4385
|
-
const initValue = React.useMemo(() => (initialVale == null ?
|
|
4397
|
+
const initValue = React.useMemo(() => (initialVale == null ? '' : `${initialVale}`), [initialVale]);
|
|
4386
4398
|
const [value, setValue] = React.useState(initValue);
|
|
4387
|
-
const helpText = props.helpText ??
|
|
4399
|
+
const helpText = props.helpText ?? 'Press tab to save';
|
|
4388
4400
|
const invalid = React.useCallback(() => TextInputValidator(props, value, data, {}), [props, value, data]);
|
|
4389
4401
|
const save = React.useCallback(async (selectedRows) => {
|
|
4390
4402
|
if (invalid())
|
|
@@ -4404,13 +4416,13 @@ const GridFormTextArea = (props) => {
|
|
|
4404
4416
|
invalid,
|
|
4405
4417
|
save,
|
|
4406
4418
|
});
|
|
4407
|
-
return popoverWrapper(jsxRuntime.jsx("div", { className:
|
|
4419
|
+
return popoverWrapper(jsxRuntime.jsx("div", { className: 'subComponent', style: { display: 'flex', flexDirection: 'row', width: props.width ?? 240 }, children: jsxRuntime.jsx(TextAreaInput, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), placeholder: props.placeholder ?? 'Type here', helpText: helpText }) }));
|
|
4408
4420
|
};
|
|
4409
4421
|
|
|
4410
4422
|
const GridFormTextInput = (props) => {
|
|
4411
4423
|
const { field, value: initialVale, data } = useGridPopoverContext();
|
|
4412
|
-
const helpText = props.helpText ??
|
|
4413
|
-
const initValue = React.useMemo(() => (initialVale == null ?
|
|
4424
|
+
const helpText = props.helpText ?? 'Press enter or tab to save';
|
|
4425
|
+
const initValue = React.useMemo(() => (initialVale == null ? '' : `${initialVale}`), [initialVale]);
|
|
4414
4426
|
const [value, setValue] = React.useState(initValue);
|
|
4415
4427
|
const invalid = React.useCallback(() => TextInputValidator(props, value, data, {}), [data, props, value]);
|
|
4416
4428
|
const save = React.useCallback(async (selectedRows) => {
|
|
@@ -4431,7 +4443,7 @@ const GridFormTextInput = (props) => {
|
|
|
4431
4443
|
invalid,
|
|
4432
4444
|
save,
|
|
4433
4445
|
});
|
|
4434
|
-
return popoverWrapper(jsxRuntime.jsx("div", { style: { display:
|
|
4446
|
+
return popoverWrapper(jsxRuntime.jsx("div", { style: { display: 'flex', flexDirection: 'row' }, className: 'FormTest subComponent', children: jsxRuntime.jsx(TextInputFormatted, { value: value, onChange: (e) => setValue(e.target.value), error: invalid(), formatted: props.units, style: { width: props.width ?? 240 }, placeholder: props.placeholder ?? 'Type here', helpText: helpText }) }));
|
|
4435
4447
|
};
|
|
4436
4448
|
|
|
4437
4449
|
const ButtonCellRenderer = (props) => {
|
|
@@ -4443,24 +4455,24 @@ const ButtonCellRenderer = (props) => {
|
|
|
4443
4455
|
inputRef.current?.focus();
|
|
4444
4456
|
}
|
|
4445
4457
|
};
|
|
4446
|
-
api.addEventListener(
|
|
4458
|
+
api.addEventListener('cellFocused', checkFocus);
|
|
4447
4459
|
return () => {
|
|
4448
|
-
api.removeEventListener(
|
|
4460
|
+
api.removeEventListener('cellFocused', checkFocus);
|
|
4449
4461
|
};
|
|
4450
4462
|
}, [api, column, node.rowIndex]);
|
|
4451
4463
|
return (jsxRuntime.jsx(lui.LuiButton, { ref: inputRef, className: "lui-button-icon-only", size: "sm", level: "text", onClick: () => {
|
|
4452
4464
|
const selectedRows = [data];
|
|
4453
4465
|
const selectedRowIds = selectedRows.map((r) => r.id);
|
|
4454
4466
|
colDef?.cellEditorParams.onClick?.({ selectedRows, selectedRowIds });
|
|
4455
|
-
}, style: { display: colDef?.cellEditorParams?.visible?.(props) !== false ?
|
|
4467
|
+
}, style: { display: colDef?.cellEditorParams?.visible?.(props) !== false ? '' : 'none' }, children: jsxRuntime.jsx(lui.LuiIcon, { name: "ic_redo", alt: "revert", size: "md" }) }));
|
|
4456
4468
|
};
|
|
4457
4469
|
const GridButton = (colDef, editor) => {
|
|
4458
4470
|
return GridCell({
|
|
4459
4471
|
minWidth: 72,
|
|
4460
4472
|
maxWidth: 72,
|
|
4461
4473
|
resizable: false,
|
|
4462
|
-
headerClass:
|
|
4463
|
-
cellClass:
|
|
4474
|
+
headerClass: 'GridHeaderAlignCenter',
|
|
4475
|
+
cellClass: 'GridCellAlignCenter',
|
|
4464
4476
|
cellRenderer: ButtonCellRenderer,
|
|
4465
4477
|
cellEditorParams: {
|
|
4466
4478
|
...editor,
|
|
@@ -4478,15 +4490,15 @@ const BooleanCellRenderer = (props) => {
|
|
|
4478
4490
|
inputRef.current?.focus();
|
|
4479
4491
|
}
|
|
4480
4492
|
};
|
|
4481
|
-
api.addEventListener(
|
|
4493
|
+
api.addEventListener('cellFocused', checkFocus);
|
|
4482
4494
|
return () => {
|
|
4483
|
-
api.removeEventListener(
|
|
4495
|
+
api.removeEventListener('cellFocused', checkFocus);
|
|
4484
4496
|
};
|
|
4485
4497
|
}, [api, column, node.rowIndex]);
|
|
4486
4498
|
const isDisabled = !fnOrVar(colDef?.editable, props);
|
|
4487
|
-
return (jsxRuntime.jsx("div", { className: clsx(
|
|
4488
|
-
|
|
4489
|
-
|
|
4499
|
+
return (jsxRuntime.jsx("div", { className: clsx('ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper', {
|
|
4500
|
+
'ag-checked': props.value,
|
|
4501
|
+
'ag-disabled': isDisabled,
|
|
4490
4502
|
}), children: jsxRuntime.jsx("input", { type: "checkbox", className: "ag-input-field-input ag-checkbox-input", disabled: isDisabled, ref: inputRef, checked: value, onChange: () => { }, onClick: (e) => {
|
|
4491
4503
|
e.stopPropagation();
|
|
4492
4504
|
// cell has to be in edit mode
|
|
@@ -4506,7 +4518,7 @@ const BooleanCellRenderer = (props) => {
|
|
|
4506
4518
|
});
|
|
4507
4519
|
const checked = !value;
|
|
4508
4520
|
onValueChange(checked);
|
|
4509
|
-
params.onClick({ selectedRows, selectedRowIds: selectedRows.map((r) => r.id), checked })
|
|
4521
|
+
void params.onClick({ selectedRows, selectedRowIds: selectedRows.map((r) => r.id), checked });
|
|
4510
4522
|
} }) }));
|
|
4511
4523
|
};
|
|
4512
4524
|
const GridEditBoolean = (colDef, editorProps) => {
|
|
@@ -4520,8 +4532,8 @@ const GridEditBoolean = (colDef, editorProps) => {
|
|
|
4520
4532
|
singleClickEdit: true,
|
|
4521
4533
|
resizable: false,
|
|
4522
4534
|
editable: true,
|
|
4523
|
-
cellClass:
|
|
4524
|
-
headerClass:
|
|
4535
|
+
cellClass: 'GridCellAlignCenter',
|
|
4536
|
+
headerClass: 'GridHeaderAlignCenter',
|
|
4525
4537
|
...colDef,
|
|
4526
4538
|
});
|
|
4527
4539
|
};
|
|
@@ -4531,7 +4543,7 @@ const GridPopoutEditMultiSelect = (colDef, props) => GridCell(colDef, {
|
|
|
4531
4543
|
...props,
|
|
4532
4544
|
editorParams: {
|
|
4533
4545
|
...props.editorParams,
|
|
4534
|
-
className: clsx(
|
|
4546
|
+
className: clsx('GridMultiSelect-containerMedium', props.editorParams?.className),
|
|
4535
4547
|
},
|
|
4536
4548
|
});
|
|
4537
4549
|
|
|
@@ -4540,47 +4552,19 @@ const GridPopoutEditMultiSelectGrid = (colDef, props) => GridCell(colDef, {
|
|
|
4540
4552
|
...props,
|
|
4541
4553
|
editorParams: {
|
|
4542
4554
|
...props.editorParams,
|
|
4543
|
-
className: clsx(
|
|
4544
|
-
},
|
|
4545
|
-
});
|
|
4546
|
-
|
|
4547
|
-
const GridRenderPopoutMenuCell = (props) => {
|
|
4548
|
-
const disabled = !fnOrVar(props.colDef?.editable, props);
|
|
4549
|
-
return (jsxRuntime.jsx(lui.LuiIcon, { name: "ic_more_vert", alt: "More actions", size: "md", className: clsx("GridPopoutMenu-burger", disabled && "GridPopoutMenu-burgerDisabled") }));
|
|
4550
|
-
};
|
|
4551
|
-
|
|
4552
|
-
/**
|
|
4553
|
-
* Popout burger menu
|
|
4554
|
-
*/
|
|
4555
|
-
const GridPopoverMenu = (colDef, custom) => GridCell({
|
|
4556
|
-
minWidth: 48,
|
|
4557
|
-
maxWidth: 48,
|
|
4558
|
-
width: 40,
|
|
4559
|
-
sortable: false,
|
|
4560
|
-
editable: colDef.editable != null ? colDef.editable : true,
|
|
4561
|
-
exportable: false,
|
|
4562
|
-
cellStyle: { flex: 1, justifyContent: "center" },
|
|
4563
|
-
cellRenderer: GridRenderPopoutMenuCell,
|
|
4564
|
-
...colDef,
|
|
4565
|
-
cellRendererParams: {
|
|
4566
|
-
// Menus open on single click, this parameter is picked up in Grid.tsx
|
|
4567
|
-
singleClickEdit: true,
|
|
4555
|
+
className: clsx('GridMultiSelect-containerMedium', props.editorParams?.className),
|
|
4568
4556
|
},
|
|
4569
|
-
}, {
|
|
4570
|
-
editor: GridFormPopoverMenu,
|
|
4571
|
-
preventAutoEdit: true,
|
|
4572
|
-
...custom,
|
|
4573
4557
|
});
|
|
4574
4558
|
|
|
4575
4559
|
const GridPopoverEditBearingLike = (colDef, props) => GridCell({
|
|
4576
|
-
valueFormatter: (params) => props.editorParams?.formatValue(params.value) ??
|
|
4560
|
+
valueFormatter: (params) => props.editorParams?.formatValue(params.value) ?? '',
|
|
4577
4561
|
...colDef,
|
|
4578
4562
|
}, {
|
|
4579
4563
|
editor: GridFormEditBearing,
|
|
4580
4564
|
...props,
|
|
4581
4565
|
});
|
|
4582
4566
|
const GridPopoverEditBearingEditorParams = {
|
|
4583
|
-
placeHolder:
|
|
4567
|
+
placeHolder: 'Enter bearing',
|
|
4584
4568
|
formatValue: bearingValueFormatter,
|
|
4585
4569
|
range: bearingRangeValidator,
|
|
4586
4570
|
};
|
|
@@ -4592,7 +4576,7 @@ const GridPopoverEditBearing = (colDef, props) => GridPopoverEditBearingLike(col
|
|
|
4592
4576
|
},
|
|
4593
4577
|
});
|
|
4594
4578
|
const GridPopoverEditBearingCorrectionEditorParams = {
|
|
4595
|
-
placeHolder:
|
|
4579
|
+
placeHolder: 'Enter bearing correction',
|
|
4596
4580
|
formatValue: bearingCorrectionValueFormatter,
|
|
4597
4581
|
range: bearingCorrectionRangeValidator,
|
|
4598
4582
|
};
|
|
@@ -4610,11 +4594,39 @@ const GridPopoverEditDropDown = (colDef, props) => GridCell(colDef, {
|
|
|
4610
4594
|
editorParams: {
|
|
4611
4595
|
...props.editorParams,
|
|
4612
4596
|
className: clsx({
|
|
4613
|
-
|
|
4597
|
+
'GridPopoverEditDropDown-containerLarge': !props.editorParams?.className?.includes('GridPopoverEditDropDown-container'),
|
|
4614
4598
|
}, props.editorParams?.className),
|
|
4615
4599
|
},
|
|
4616
4600
|
});
|
|
4617
4601
|
|
|
4602
|
+
const GridRenderPopoutMenuCell = (props) => {
|
|
4603
|
+
const disabled = !fnOrVar(props.colDef?.editable, props);
|
|
4604
|
+
return (jsxRuntime.jsx(lui.LuiIcon, { name: 'ic_more_vert', alt: 'More actions', size: 'md', className: clsx('GridPopoutMenu-burger', disabled && 'GridPopoutMenu-burgerDisabled') }));
|
|
4605
|
+
};
|
|
4606
|
+
|
|
4607
|
+
/**
|
|
4608
|
+
* Popout burger menu
|
|
4609
|
+
*/
|
|
4610
|
+
const GridPopoverMenu = (colDef, custom) => GridCell({
|
|
4611
|
+
minWidth: 48,
|
|
4612
|
+
maxWidth: 48,
|
|
4613
|
+
width: 40,
|
|
4614
|
+
sortable: false,
|
|
4615
|
+
editable: colDef.editable != null ? colDef.editable : true,
|
|
4616
|
+
exportable: false,
|
|
4617
|
+
cellStyle: { flex: 1, justifyContent: 'center' },
|
|
4618
|
+
cellRenderer: GridRenderPopoutMenuCell,
|
|
4619
|
+
...colDef,
|
|
4620
|
+
cellRendererParams: {
|
|
4621
|
+
// Menus open on single click, this parameter is picked up in Grid.tsx
|
|
4622
|
+
singleClickEdit: true,
|
|
4623
|
+
},
|
|
4624
|
+
}, {
|
|
4625
|
+
editor: GridFormPopoverMenu,
|
|
4626
|
+
preventAutoEdit: true,
|
|
4627
|
+
...custom,
|
|
4628
|
+
});
|
|
4629
|
+
|
|
4618
4630
|
const GridPopoverMessage = (colDef, props) => GridCell({
|
|
4619
4631
|
resizable: true,
|
|
4620
4632
|
...colDef,
|
|
@@ -4634,9 +4646,9 @@ const GridPopoverTextInput = (colDef, params) => GridCell(colDef, {
|
|
|
4634
4646
|
...params,
|
|
4635
4647
|
});
|
|
4636
4648
|
|
|
4637
|
-
const GridWrapper = ({ children, maxHeight }) => (jsxRuntime.jsx("div", { className:
|
|
4649
|
+
const GridWrapper = ({ children, maxHeight }) => (jsxRuntime.jsx("div", { className: 'Grid-wrapper', style: { maxHeight }, children: children }));
|
|
4638
4650
|
|
|
4639
|
-
const getColId = (colDef) => colDef.colId ??
|
|
4651
|
+
const getColId = (colDef) => colDef.colId ?? '';
|
|
4640
4652
|
const isFlexColumn = (colDef) => !!colDef.flex && !isGridCellFiller(colDef);
|
|
4641
4653
|
|
|
4642
4654
|
/**
|
|
@@ -4648,7 +4660,7 @@ const GridContextProvider = (props) => {
|
|
|
4648
4660
|
const { modifyUpdating, checkUpdating } = React.useContext(GridUpdatingContext);
|
|
4649
4661
|
const [gridApi, setGridApi] = React.useState();
|
|
4650
4662
|
const [gridReady, setGridReady] = React.useState(false);
|
|
4651
|
-
const [quickFilter, _setQuickFilter] = React.useState(
|
|
4663
|
+
const [quickFilter, _setQuickFilter] = React.useState('');
|
|
4652
4664
|
const [invisibleColumnIds, _setInvisibleColumnIds] = React.useState();
|
|
4653
4665
|
const testId = React.useRef();
|
|
4654
4666
|
const idsBeforeUpdate = React.useRef([]);
|
|
@@ -4668,7 +4680,7 @@ const GridContextProvider = (props) => {
|
|
|
4668
4680
|
* Set quick filter directly on grid, based on previously save quickFilter state.
|
|
4669
4681
|
*/
|
|
4670
4682
|
React.useEffect(() => {
|
|
4671
|
-
gridApi?.setGridOption(
|
|
4683
|
+
gridApi?.setGridOption('quickFilterText', quickFilter);
|
|
4672
4684
|
}, [gridApi, quickFilter]);
|
|
4673
4685
|
/**
|
|
4674
4686
|
* Wraps things that require gridApi in common handling, for when gridApi not present.
|
|
@@ -4701,9 +4713,9 @@ const GridContextProvider = (props) => {
|
|
|
4701
4713
|
let id = 0;
|
|
4702
4714
|
try {
|
|
4703
4715
|
gridApi?.forEachNodeAfterFilterAndSort((rowNode) => {
|
|
4704
|
-
id = parseInt(rowNode.id ??
|
|
4716
|
+
id = parseInt(rowNode.id ?? '0');
|
|
4705
4717
|
// this is the only way to get out of the loop
|
|
4706
|
-
throw
|
|
4718
|
+
throw 'expected exception - exit_loop';
|
|
4707
4719
|
});
|
|
4708
4720
|
}
|
|
4709
4721
|
catch (ex) {
|
|
@@ -4717,7 +4729,7 @@ const GridContextProvider = (props) => {
|
|
|
4717
4729
|
const setApis = React.useCallback((gridApi, dataTestId) => {
|
|
4718
4730
|
testId.current = dataTestId;
|
|
4719
4731
|
setGridApi(gridApi);
|
|
4720
|
-
gridApi?.setGridOption(
|
|
4732
|
+
gridApi?.setGridOption('quickFilterText', quickFilter);
|
|
4721
4733
|
setGridReady(!!gridApi);
|
|
4722
4734
|
}, [quickFilter]);
|
|
4723
4735
|
/**
|
|
@@ -4727,9 +4739,9 @@ const GridContextProvider = (props) => {
|
|
|
4727
4739
|
if (!gridApi)
|
|
4728
4740
|
return null;
|
|
4729
4741
|
if (!gridApi.getDisplayedRowCount())
|
|
4730
|
-
return
|
|
4742
|
+
return 'empty';
|
|
4731
4743
|
if (!lodashEs.isEmpty(gridApi.getRenderedNodes()))
|
|
4732
|
-
return
|
|
4744
|
+
return 'rows-visible';
|
|
4733
4745
|
// If there are rows to render, but there are no rendered nodes then we should wait
|
|
4734
4746
|
return null;
|
|
4735
4747
|
}, [gridApi]);
|
|
@@ -4785,7 +4797,7 @@ const GridContextProvider = (props) => {
|
|
|
4785
4797
|
* Uses beforeUpdate ids to find new nodes.
|
|
4786
4798
|
*/
|
|
4787
4799
|
const _getNewNodes = React.useCallback(() => {
|
|
4788
|
-
return gridApiOp((gridApi) => lodashEs.compact(lodashEs.difference(_getAllRowIds(), idsBeforeUpdate.current).map((rowId) => gridApi.getRowNode(
|
|
4800
|
+
return gridApiOp((gridApi) => lodashEs.compact(lodashEs.difference(_getAllRowIds(), idsBeforeUpdate.current).map((rowId) => gridApi.getRowNode('' + rowId))), () => []);
|
|
4789
4801
|
}, [_getAllRowIds, gridApiOp]);
|
|
4790
4802
|
/**
|
|
4791
4803
|
* Get grid nodes via rowIds. If rowIds has no matching node the result may be smaller than expected.
|
|
@@ -4794,7 +4806,7 @@ const GridContextProvider = (props) => {
|
|
|
4794
4806
|
* @param rowIds Row ids to get from grid.
|
|
4795
4807
|
*/
|
|
4796
4808
|
const _rowIdsToNodes = React.useCallback((rowIds) => {
|
|
4797
|
-
return gridApiOp((gridApi) => lodashEs.compact(rowIds.map((rowId) => gridApi.getRowNode(
|
|
4809
|
+
return gridApiOp((gridApi) => lodashEs.compact(rowIds.map((rowId) => gridApi.getRowNode('' + rowId))), () => []);
|
|
4798
4810
|
}, [gridApiOp]);
|
|
4799
4811
|
/**
|
|
4800
4812
|
* Get ColDefs, with flattened ColGroupDefs
|
|
@@ -4935,7 +4947,7 @@ const GridContextProvider = (props) => {
|
|
|
4935
4947
|
gridApi.autoSizeColumns(colsToResize.map((colState) => colState.colId), skipHeader);
|
|
4936
4948
|
}
|
|
4937
4949
|
return {
|
|
4938
|
-
width: lodashEs.sumBy(gridApi.getColumnState().filter((col) => !col.hide),
|
|
4950
|
+
width: lodashEs.sumBy(gridApi.getColumnState().filter((col) => !col.hide), 'width'),
|
|
4939
4951
|
};
|
|
4940
4952
|
}, [gridApi]);
|
|
4941
4953
|
/**
|
|
@@ -4952,7 +4964,9 @@ const GridContextProvider = (props) => {
|
|
|
4952
4964
|
}
|
|
4953
4965
|
gridApi.stopEditing();
|
|
4954
4966
|
}, [gridApi]);
|
|
4955
|
-
const startCellEditing = React.useCallback(
|
|
4967
|
+
const startCellEditing = React.useCallback(
|
|
4968
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
4969
|
+
({ rowId, colId }) => {
|
|
4956
4970
|
if (!gridApi)
|
|
4957
4971
|
return;
|
|
4958
4972
|
const colDef = gridApi.getColumnDef(colId);
|
|
@@ -4967,7 +4981,7 @@ const GridContextProvider = (props) => {
|
|
|
4967
4981
|
rowNode.setSelected(true, true);
|
|
4968
4982
|
}
|
|
4969
4983
|
// Cell already being edited, so don't re-edit until finished
|
|
4970
|
-
if (checkUpdating([colDef.field ??
|
|
4984
|
+
if (checkUpdating([colDef.field ?? ''], rowId)) {
|
|
4971
4985
|
return;
|
|
4972
4986
|
}
|
|
4973
4987
|
const rowIndex = rowNode.rowIndex;
|
|
@@ -5038,11 +5052,11 @@ const GridContextProvider = (props) => {
|
|
|
5038
5052
|
return await gridApiOp(async (gridApi) => {
|
|
5039
5053
|
const selectedRows = props.selectedRows;
|
|
5040
5054
|
let ok = false;
|
|
5041
|
-
await modifyUpdating(props.field ??
|
|
5055
|
+
await modifyUpdating(props.field ?? '', selectedRows.map((data) => data.id), async () => {
|
|
5042
5056
|
// Need to refresh to get spinners to work on all rows
|
|
5043
5057
|
gridApi.refreshCells({ rowNodes: props.selectedRows, force: true });
|
|
5044
5058
|
ok = await fnUpdate(selectedRows).catch((ex) => {
|
|
5045
|
-
console.error(
|
|
5059
|
+
console.error('Exception during modifyUpdating', ex);
|
|
5046
5060
|
return false;
|
|
5047
5061
|
});
|
|
5048
5062
|
});
|
|
@@ -5079,7 +5093,7 @@ const GridContextProvider = (props) => {
|
|
|
5079
5093
|
}
|
|
5080
5094
|
catch (ex) {
|
|
5081
5095
|
// Hide errors in jest, but log them in browser
|
|
5082
|
-
if (typeof jest ===
|
|
5096
|
+
if (typeof jest === 'undefined')
|
|
5083
5097
|
console.error(ex);
|
|
5084
5098
|
}
|
|
5085
5099
|
}, 50), [gridApi]);
|
|
@@ -5101,7 +5115,7 @@ const GridContextProvider = (props) => {
|
|
|
5101
5115
|
gridApi?.forEachNodeAfterFilter((rowNode) => {
|
|
5102
5116
|
arr.push(rowNode.id);
|
|
5103
5117
|
});
|
|
5104
|
-
return arr.join(
|
|
5118
|
+
return arr.join('|');
|
|
5105
5119
|
};
|
|
5106
5120
|
if (gridApi) {
|
|
5107
5121
|
const hasFocusedCell = gridApi.getFocusedCell();
|
|
@@ -5115,11 +5129,11 @@ const GridContextProvider = (props) => {
|
|
|
5115
5129
|
}, 200), [gridApi]);
|
|
5116
5130
|
const addExternalFilter = (filter) => {
|
|
5117
5131
|
externalFilters.current.push(filter);
|
|
5118
|
-
onFilterChanged()
|
|
5132
|
+
void onFilterChanged();
|
|
5119
5133
|
};
|
|
5120
5134
|
const removeExternalFilter = (filter) => {
|
|
5121
5135
|
lodashEs.remove(externalFilters.current, (v) => v === filter);
|
|
5122
|
-
onFilterChanged()
|
|
5136
|
+
void onFilterChanged();
|
|
5123
5137
|
};
|
|
5124
5138
|
const isExternalFilterPresent = () => !lodashEs.isEmpty(externalFilters.current);
|
|
5125
5139
|
const doesExternalFilterPass = (node) => externalFilters.current.every((filter) => filter(node.data, node));
|
|
@@ -5223,10 +5237,10 @@ const GridContextProvider = (props) => {
|
|
|
5223
5237
|
const downloadCsvUseValueFormattersProcessCellCallback = (params) => {
|
|
5224
5238
|
const encodeToString = (value) => {
|
|
5225
5239
|
// Convert nullish values to blank
|
|
5226
|
-
if (value ===
|
|
5227
|
-
return
|
|
5240
|
+
if (value === '-' || value === '–' || value == null) {
|
|
5241
|
+
return '';
|
|
5228
5242
|
}
|
|
5229
|
-
if (typeof value ===
|
|
5243
|
+
if (typeof value === 'string') {
|
|
5230
5244
|
return value;
|
|
5231
5245
|
}
|
|
5232
5246
|
return JSON.stringify(value);
|
|
@@ -5240,19 +5254,19 @@ const downloadCsvUseValueFormattersProcessCellCallback = (params) => {
|
|
|
5240
5254
|
const valueFormatter = colDef.valueFormatter;
|
|
5241
5255
|
// If no valueFormatter then value _must_ be a string
|
|
5242
5256
|
if (valueFormatter == null) {
|
|
5243
|
-
if (params.value != null && typeof params.value !==
|
|
5257
|
+
if (params.value != null && typeof params.value !== 'string') {
|
|
5244
5258
|
console.error(`downloadCsv: valueFormatter missing and getValue is not a string, colId: ${colDef.colId}`);
|
|
5245
5259
|
}
|
|
5246
5260
|
return encodeToString(params.value);
|
|
5247
5261
|
}
|
|
5248
5262
|
// We don't have access to registered functions, so we can't call them
|
|
5249
|
-
if (typeof valueFormatter !==
|
|
5263
|
+
if (typeof valueFormatter !== 'function') {
|
|
5250
5264
|
console.error(`downloadCsv: String type (registered) value formatters are unsupported in downloadCsv, colId: ${colDef.colId}`);
|
|
5251
5265
|
return encodeToString(params.value);
|
|
5252
5266
|
}
|
|
5253
5267
|
const result = valueFormatter({ ...params, data: params.node?.data, colDef, node: null });
|
|
5254
5268
|
// type may not be string due to casting, leave the type check in
|
|
5255
|
-
if (params.value != null && typeof result !==
|
|
5269
|
+
if (params.value != null && typeof result !== 'string') {
|
|
5256
5270
|
console.error(`downloadCsv: valueFormatter is returning non string values, colDef:", colId: ${colDef.colId}`);
|
|
5257
5271
|
}
|
|
5258
5272
|
// We add an extra encodeToString here just in case valueFormatter is returning non string values
|
|
@@ -5311,7 +5325,7 @@ const usePrevious = (value) => {
|
|
|
5311
5325
|
|
|
5312
5326
|
// Kept this less than one second, so I don't have issues with waitFor as it defaults to 1s
|
|
5313
5327
|
const minimumInProgressTimeMs = 950;
|
|
5314
|
-
const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style, className, title, onClick, size =
|
|
5328
|
+
const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style, className, title, onClick, size = 'sm', iconPosition = 'left', level = 'tertiary', 'aria-label': ariaLabel, }) => {
|
|
5315
5329
|
const [inProgress, setInProgress] = React.useState(false);
|
|
5316
5330
|
const lastInProgress = usePrevious(inProgress ?? false);
|
|
5317
5331
|
const [localInProgress, setLocalInProgress, setLocalInProgressDeferred] = useStateDeferred(inProgress);
|
|
@@ -5320,28 +5334,28 @@ const ActionButton = ({ icon, name, inProgressName, disabled, dataTestId, style,
|
|
|
5320
5334
|
return;
|
|
5321
5335
|
inProgress ? setLocalInProgress(true) : setLocalInProgressDeferred(false, minimumInProgressTimeMs);
|
|
5322
5336
|
}, [inProgress, lastInProgress, setLocalInProgress, setLocalInProgressDeferred]);
|
|
5323
|
-
const buttonText = (jsxRuntime.jsxs("span", { className:
|
|
5324
|
-
return (jsxRuntime.jsxs(lui.LuiButton, { "data-testid": dataTestId, type:
|
|
5337
|
+
const buttonText = (jsxRuntime.jsxs("span", { className: 'ActionButton-minimalArea', children: [jsxRuntime.jsx("span", { className: 'ActionButton-minimalAreaDisplay', children: (localInProgress ? inProgressName : name) ?? name }), jsxRuntime.jsx("span", { className: 'ActionButton-minimalAreaExpand', children: name })] }));
|
|
5338
|
+
return (jsxRuntime.jsxs(lui.LuiButton, { "data-testid": dataTestId, type: 'button', level: level, title: title ?? ariaLabel ?? name, buttonProps: { 'aria-label': ariaLabel ?? name }, className: clsx('lui-button-icon-right', 'ActionButton', className, localInProgress && 'ActionButton-inProgress', name != null && !className?.includes('ActionButton-fill') && 'ActionButton-minimal', name == null && 'ActionButton-iconOnly'), size: 'lg', style: style, onClick: () => {
|
|
5325
5339
|
const promise = onClick();
|
|
5326
|
-
const isPromise = typeof promise !==
|
|
5340
|
+
const isPromise = typeof promise !== 'undefined';
|
|
5327
5341
|
if (isPromise) {
|
|
5328
5342
|
setInProgress(true);
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5343
|
+
void promise.finally(() => {
|
|
5344
|
+
setInProgress(false);
|
|
5345
|
+
});
|
|
5332
5346
|
}
|
|
5333
|
-
}, disabled: localInProgress || disabled, children: [iconPosition ===
|
|
5334
|
-
|
|
5347
|
+
}, disabled: localInProgress || disabled, children: [iconPosition === 'right' && buttonText, localInProgress && (jsxRuntime.jsx("div", { style: { position: 'relative' }, children: jsxRuntime.jsx(lui.LuiMiniSpinner, { size: 14, divProps: {
|
|
5348
|
+
'data-testid': 'loading-spinner',
|
|
5335
5349
|
style: {
|
|
5336
|
-
position:
|
|
5350
|
+
position: 'absolute',
|
|
5337
5351
|
left: 4,
|
|
5338
5352
|
top: -10,
|
|
5339
5353
|
bottom: 10,
|
|
5340
5354
|
right: -4,
|
|
5341
5355
|
},
|
|
5342
|
-
role:
|
|
5343
|
-
|
|
5344
|
-
} }) })), jsxRuntime.jsx(lui.LuiIcon, { name: icon, alt: ariaLabel ?? name ??
|
|
5356
|
+
role: 'status',
|
|
5357
|
+
'aria-label': 'Loading',
|
|
5358
|
+
} }) })), jsxRuntime.jsx(lui.LuiIcon, { name: icon, alt: ariaLabel ?? name ?? '', size: size }), iconPosition === 'left' && buttonText] }));
|
|
5345
5359
|
};
|
|
5346
5360
|
|
|
5347
5361
|
const useDeferredPromise = () => {
|