@linzjs/step-ag-grid 29.15.0 → 29.19.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/README.md +1 -1
- package/dist/index.css +27 -0
- package/dist/src/components/Grid.d.ts +3 -2
- package/dist/src/components/gridFilter/GridFilterColumnsMultiSelect.d.ts +2 -1
- package/dist/src/components/gridForm/GridFormInlineTextInput.d.ts +15 -0
- package/dist/src/components/gridForm/index.d.ts +1 -0
- package/dist/src/components/gridHook/useGridRangeSelection.d.ts +1 -1
- package/dist/src/components/gridPopoverEdit/GridInlineTextInput.d.ts +5 -0
- package/dist/src/components/gridPopoverEdit/index.d.ts +1 -0
- package/dist/src/contexts/GridContext.d.ts +1 -1
- package/dist/src/utils/__tests__/storybookTestUtil.ts +5 -1
- package/dist/step-ag-grid.cjs +233 -90
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +232 -91
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +14 -12
- package/src/components/Grid.tsx +33 -10
- package/src/components/GridPopoverHook.tsx +5 -2
- package/src/components/gridFilter/GridFilterColumnsMultiSelect.tsx +23 -4
- package/src/components/gridForm/GridFormInlineTextInput.tsx +119 -0
- package/src/components/gridForm/index.ts +1 -0
- package/src/components/gridHook/useGridContextMenu.tsx +3 -1
- package/src/components/gridHook/useGridCopy.ts +5 -2
- package/src/components/gridHook/useGridRangeSelection.ts +25 -4
- package/src/components/gridPopoverEdit/GridInlineTextInput.ts +13 -0
- package/src/components/gridPopoverEdit/index.ts +1 -0
- package/src/contexts/GridContext.tsx +6 -1
- package/src/contexts/GridContextProvider.tsx +30 -13
- package/src/stories/grid/GridFilterColumnsMultiSelect.stories.tsx +52 -7
- package/src/stories/grid/GridInlineText.stories.tsx +185 -0
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +3 -3
- package/src/styles/Grid.scss +5 -0
- package/src/styles/GridFormInlineTextInput.scss +23 -0
- package/src/styles/index.scss +1 -1
- package/src/utils/__tests__/storybookTestUtil.ts +5 -1
package/dist/step-ag-grid.cjs
CHANGED
|
@@ -2634,8 +2634,9 @@ const useGridContextMenu = ({ contextMenuSelectRow, contextMenu: ContextMenu, co
|
|
|
2634
2634
|
const clickedRowRef = React.useRef(null);
|
|
2635
2635
|
const eventRef = React.useRef(undefined);
|
|
2636
2636
|
const openMenu = React.useCallback((e) => {
|
|
2637
|
-
if (!e)
|
|
2637
|
+
if (!e) {
|
|
2638
2638
|
return;
|
|
2639
|
+
}
|
|
2639
2640
|
prePopupOps();
|
|
2640
2641
|
setAnchorPoint({ x: e.clientX, y: e.clientY });
|
|
2641
2642
|
setOpen(true);
|
|
@@ -2905,7 +2906,11 @@ const useGridCopy = ({ ranges, rangeStartRef, rangeEndRef, hasSelectedMoreThanOn
|
|
|
2905
2906
|
contextMenu: (GridRangeSelectContextMenu),
|
|
2906
2907
|
context: { onCopy, copyType, setCopyType },
|
|
2907
2908
|
});
|
|
2908
|
-
const rangeSelectInterceptContextMenu = React.useCallback((event) =>
|
|
2909
|
+
const rangeSelectInterceptContextMenu = React.useCallback((event) => {
|
|
2910
|
+
return hasSelectedMoreThanOneCellRef.current && rangeStartRef.current !== null
|
|
2911
|
+
? rangeSelectContextMenu(event)
|
|
2912
|
+
: cellContextMenu(event);
|
|
2913
|
+
}, [cellContextMenu, rangeSelectContextMenu]);
|
|
2909
2914
|
return {
|
|
2910
2915
|
onCopyEvent,
|
|
2911
2916
|
rangeSelectInterceptContextMenu,
|
|
@@ -3029,6 +3034,23 @@ const useGridRangeSelection = ({ enableRangeSelection, gridDivRef, rangeStartRef
|
|
|
3029
3034
|
rangeEndRef.current = null;
|
|
3030
3035
|
updateRangeSelectionCellClasses();
|
|
3031
3036
|
}, [updateRangeSelectionCellClasses]);
|
|
3037
|
+
const mouseDownRef = React.useRef([0, 0]);
|
|
3038
|
+
const trackMouseDown = React.useCallback((e) => {
|
|
3039
|
+
mouseDownRef.current = [e.screenX, e.screenY];
|
|
3040
|
+
}, []);
|
|
3041
|
+
const trackMouseUp = React.useCallback((e) => {
|
|
3042
|
+
if (rangeEndRef.current) {
|
|
3043
|
+
rangeEndRef.current.clickLocation = [e.screenX, e.screenY];
|
|
3044
|
+
}
|
|
3045
|
+
}, []);
|
|
3046
|
+
React.useEffect(() => {
|
|
3047
|
+
document.addEventListener('mousedown', trackMouseDown, { capture: true });
|
|
3048
|
+
document.addEventListener('mouseup', trackMouseUp, { capture: true });
|
|
3049
|
+
return () => {
|
|
3050
|
+
document.removeEventListener('mousemove', trackMouseDown, { capture: true });
|
|
3051
|
+
document.removeEventListener('mouseup', trackMouseUp, { capture: true });
|
|
3052
|
+
};
|
|
3053
|
+
}, []);
|
|
3032
3054
|
const onCellMouseOver = React.useCallback((e, mouseDown) => {
|
|
3033
3055
|
if (!enableRangeSelection) {
|
|
3034
3056
|
return;
|
|
@@ -3042,19 +3064,20 @@ const useGridRangeSelection = ({ enableRangeSelection, gridDivRef, rangeStartRef
|
|
|
3042
3064
|
rangeEndRef.current = {
|
|
3043
3065
|
rowId: e.node.data.id,
|
|
3044
3066
|
colId: e.column.getColId(),
|
|
3045
|
-
|
|
3067
|
+
clickLocation: [0, 0],
|
|
3046
3068
|
};
|
|
3047
3069
|
if (mouseDown) {
|
|
3048
3070
|
const sortedNodes = [];
|
|
3049
3071
|
e.api.forEachNodeAfterFilterAndSort((node) => sortedNodes.push(node));
|
|
3050
3072
|
rangeSortedNodesRef.current = sortedNodes;
|
|
3051
3073
|
setRefreshIntervalEnabled(true);
|
|
3052
|
-
rangeStartRef.current = { ...rangeEndRef.current };
|
|
3074
|
+
rangeStartRef.current = { ...rangeEndRef.current, clickLocation: mouseDownRef.current };
|
|
3053
3075
|
}
|
|
3054
3076
|
if (rangeStartRef.current &&
|
|
3055
3077
|
rangeEndRef.current &&
|
|
3056
3078
|
(rangeStartRef.current.rowId !== rangeEndRef.current.rowId ||
|
|
3057
3079
|
rangeStartRef.current.colId !== rangeEndRef.current.colId)) {
|
|
3080
|
+
e.api.stopEditing();
|
|
3058
3081
|
hasSelectedMoreThanOneCellRef.current = true;
|
|
3059
3082
|
window.getSelection()?.removeAllRanges();
|
|
3060
3083
|
}
|
|
@@ -3259,7 +3282,7 @@ defaultPostSort = true, rowData, rowHeight = theme === 'ag-theme-step-default' ?
|
|
|
3259
3282
|
// ─── Selection ────────────────────────────────
|
|
3260
3283
|
autoSelectFirstRow, enableRangeSelection = false, externalSelectedIds, externalSelectedItems, selectColumnPinned = 'left', selectable, setExternalSelectedIds, setExternalSelectedItems,
|
|
3261
3284
|
// ─── Editing ──────────────────────────────────
|
|
3262
|
-
singleClickEdit = false,
|
|
3285
|
+
singleClickEdit = false, enableMultilineBulkEdit = false,
|
|
3263
3286
|
// ─── Context Menu ─────────────────────────────
|
|
3264
3287
|
contextMenuSelectRow = false, contextMenu,
|
|
3265
3288
|
// ─── Callbacks / Events ───────────────────────
|
|
@@ -3541,10 +3564,16 @@ maxInitialWidth,
|
|
|
3541
3564
|
* When grid is ready set the apis to the grid context and sync selected items to grid.
|
|
3542
3565
|
*/
|
|
3543
3566
|
const onGridReady = React.useCallback((event) => {
|
|
3544
|
-
setApis(event.api, hasExternallySelectedItems, dataTestId);
|
|
3567
|
+
setApis(event.api, hasExternallySelectedItems, enableMultilineBulkEdit, dataTestId);
|
|
3545
3568
|
event.api.showNoRowsOverlay();
|
|
3546
3569
|
synchroniseExternallySelectedItemsToGrid();
|
|
3547
|
-
}, [
|
|
3570
|
+
}, [
|
|
3571
|
+
dataTestId,
|
|
3572
|
+
enableMultilineBulkEdit,
|
|
3573
|
+
hasExternallySelectedItems,
|
|
3574
|
+
setApis,
|
|
3575
|
+
synchroniseExternallySelectedItemsToGrid,
|
|
3576
|
+
]);
|
|
3548
3577
|
/**
|
|
3549
3578
|
* When the grid is being initialized the data may be empty.
|
|
3550
3579
|
* This will resize columns when we have at least one row.
|
|
@@ -3587,6 +3616,11 @@ maxInitialWidth,
|
|
|
3587
3616
|
* Handle double click edit
|
|
3588
3617
|
*/
|
|
3589
3618
|
const onCellDoubleClick = React.useCallback((event) => {
|
|
3619
|
+
const cellEditing = event.api.getEditingCells()?.[0];
|
|
3620
|
+
if (cellEditing && cellEditing.colId === event.column.getColId() && cellEditing.rowIndex === event.rowIndex) {
|
|
3621
|
+
// Ignore double click in already editing cell
|
|
3622
|
+
return;
|
|
3623
|
+
}
|
|
3590
3624
|
const editable = fnOrVar(event.colDef?.editable, event);
|
|
3591
3625
|
if (editable && !invokeEditAction(event)) {
|
|
3592
3626
|
void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
|
|
@@ -3671,18 +3705,25 @@ maxInitialWidth,
|
|
|
3671
3705
|
* Handle single click edits
|
|
3672
3706
|
*/
|
|
3673
3707
|
const onCellClicked = React.useCallback((event) => {
|
|
3674
|
-
if (rangeStartRef.current && rangeEndRef.current) {
|
|
3708
|
+
if (enableRangeSelection && rangeStartRef.current && rangeEndRef.current) {
|
|
3675
3709
|
// This is to detect difference between a single click and a click drag return to cell.
|
|
3676
|
-
|
|
3677
|
-
|
|
3710
|
+
const maxDistanceBetweenC = Math.max(Math.abs(rangeEndRef.current.clickLocation[0] - rangeStartRef.current.clickLocation[0]), Math.abs(rangeEndRef.current.clickLocation[1] - rangeStartRef.current.clickLocation[1]));
|
|
3711
|
+
if (maxDistanceBetweenC > 8) {
|
|
3712
|
+
return;
|
|
3678
3713
|
}
|
|
3679
|
-
|
|
3714
|
+
clearRangeSelection();
|
|
3680
3715
|
}
|
|
3681
3716
|
const editable = fnOrVar(event.colDef?.editable, event);
|
|
3682
3717
|
if ((editable && event.colDef.singleClickEdit) ?? singleClickEdit) {
|
|
3718
|
+
const editingCell = event.api.getEditingCells()[0];
|
|
3719
|
+
// If we are editing and single click we don't want the editing to stop
|
|
3720
|
+
if (editingCell && editingCell.colId === event.column.getColId() && editingCell.rowIndex === event.rowIndex) {
|
|
3721
|
+
return;
|
|
3722
|
+
}
|
|
3723
|
+
event.api.setFocusedCell(event.rowIndex ?? 0, event.column.getColId(), event.rowPinned);
|
|
3683
3724
|
void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
|
|
3684
3725
|
}
|
|
3685
|
-
}, [clearRangeSelection, singleClickEdit, startCellEditing]);
|
|
3726
|
+
}, [clearRangeSelection, enableRangeSelection, singleClickEdit, startCellEditing]);
|
|
3686
3727
|
/**
|
|
3687
3728
|
* Set of column I'd's that are prevented from auto-sizing as they are user set
|
|
3688
3729
|
*/
|
|
@@ -3963,7 +4004,7 @@ maxInitialWidth,
|
|
|
3963
4004
|
event.api.sizeColumnsToFit();
|
|
3964
4005
|
}
|
|
3965
4006
|
}, [sizeColumns]);
|
|
3966
|
-
return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready'), children: [contextMenuComponent, rangeSelectContextMenuComponent, jsxRuntime.jsx("div", { style: { flex: 1 }, ref: gridDivRef, onCopy: onCopyEvent, children: jsxRuntime.jsx(agGridReact.AgGridReact, { theme: 'legacy', domLayout: params.domLayout, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, getRowId: getRowId, rowData: rowData, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, animateRows: params.animateRows ?? false, doesExternalFilterPass: doesExternalFilterPass, isExternalFilterPresent: isExternalFilterPresent, maintainColumnOrder: true, noRowsOverlayComponent: noRowsOverlayComponent, onCellClicked: onCellClicked, onCellContextMenu: rangeSelectInterceptContextMenu, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellMouseDown: onCellMouseDown, onCellMouseOver: onCellMouseOver, onColumnMoved: columnMoved, onColumnResized: onColumnResized, onColumnVisible: () => void setInitialContentSize(), onGridReady: onGridReady, onGridSizeChanged: onGridSizeChanged, onModelUpdated: onModelUpdated, onRowClicked: params.onRowClicked, onRowDataUpdated: onRowDataUpdated, onRowDoubleClicked: params.onRowDoubleClicked, onRowDragCancel: clearHighlightRowClasses, onRowDragEnd: onRowDragEnd, onRowDragMove: onRowDragMove, onSelectionChanged: synchroniseExternalStateToGridSelection, onSortChanged: onSortChanged, pinnedBottomRowData: params.pinnedBottomRowData, pinnedTopRowData: params.pinnedTopRowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, preventDefaultOnContextMenu: true, quickFilterParser: quickFilterParser, rowClassRules: params.rowClassRules, rowDragText: params.rowDragText, rowHeight: rowHeight, rowSelection: selectable
|
|
4007
|
+
return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx('Grid-container', theme, 'theme-specific', staleGrid && 'Grid-sortIsStale', gridReady && rowData && autoSized && 'Grid-ready', params.hideSelectedRow && 'Grid-hideSelectedRow'), children: [contextMenuComponent, rangeSelectContextMenuComponent, jsxRuntime.jsx("div", { style: { flex: 1 }, ref: gridDivRef, onCopy: onCopyEvent, children: jsxRuntime.jsx(agGridReact.AgGridReact, { theme: 'legacy', domLayout: params.domLayout, defaultColDef: defaultColDef, columnDefs: columnDefsAdjusted, getRowId: getRowId, rowData: rowData, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, animateRows: params.animateRows ?? false, doesExternalFilterPass: doesExternalFilterPass, isExternalFilterPresent: isExternalFilterPresent, maintainColumnOrder: true, noRowsOverlayComponent: noRowsOverlayComponent, onCellClicked: onCellClicked, onCellContextMenu: rangeSelectInterceptContextMenu, onCellDoubleClicked: onCellDoubleClick, onCellEditingStopped: onCellEditingStopped, onCellFocused: onCellFocused, onCellKeyDown: onCellKeyPress, onCellMouseDown: onCellMouseDown, onCellMouseOver: onCellMouseOver, onColumnMoved: columnMoved, onColumnResized: onColumnResized, onColumnVisible: () => void setInitialContentSize(), onGridReady: onGridReady, onGridSizeChanged: onGridSizeChanged, onModelUpdated: onModelUpdated, onRowClicked: params.onRowClicked, onRowDataUpdated: onRowDataUpdated, onRowDoubleClicked: params.onRowDoubleClicked, onRowDragCancel: clearHighlightRowClasses, onRowDragEnd: onRowDragEnd, onRowDragMove: onRowDragMove, onSelectionChanged: synchroniseExternalStateToGridSelection, onSortChanged: onSortChanged, pinnedBottomRowData: params.pinnedBottomRowData, pinnedTopRowData: params.pinnedTopRowData, postSortRows: params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows, preventDefaultOnContextMenu: true, quickFilterParser: quickFilterParser, rowClassRules: params.rowClassRules, rowDragText: params.rowDragText, rowHeight: rowHeight, rowSelection: selectable
|
|
3967
4008
|
? {
|
|
3968
4009
|
enableSelectionWithoutKeys: params.enableSelectionWithoutKeys ?? false,
|
|
3969
4010
|
enableClickSelection: params.enableClickSelection ?? false,
|
|
@@ -3973,7 +4014,7 @@ maxInitialWidth,
|
|
|
3973
4014
|
headerCheckbox: false,
|
|
3974
4015
|
}),
|
|
3975
4016
|
}
|
|
3976
|
-
: undefined,
|
|
4017
|
+
: undefined, selectionColumnDef: selectionColumnDef, suppressCellFocus: params.suppressCellFocus, suppressClickEdit: true, suppressColumnVirtualisation: suppressColumnVirtualization, suppressStartEditOnTab: true }) })] }));
|
|
3977
4018
|
};
|
|
3978
4019
|
const quickFilterParser = (filterStr) => {
|
|
3979
4020
|
// filter is exact matches exactly groups separated by commas
|
|
@@ -4249,10 +4290,18 @@ class GridFilterColumnsMultiSelect {
|
|
|
4249
4290
|
const norm = this.normalizeCellValue(raw);
|
|
4250
4291
|
values.add(norm);
|
|
4251
4292
|
});
|
|
4293
|
+
const { customOrder } = this.params;
|
|
4294
|
+
const orderMap = customOrder?.length ? new Map(customOrder.map((val, idx) => [val, idx])) : null;
|
|
4252
4295
|
return Array.from(values).sort((a, b) => {
|
|
4253
|
-
if (
|
|
4254
|
-
|
|
4255
|
-
|
|
4296
|
+
if (orderMap) {
|
|
4297
|
+
const aIdx = orderMap.get(a) ?? Infinity;
|
|
4298
|
+
const bIdx = orderMap.get(b) ?? Infinity;
|
|
4299
|
+
if (aIdx !== bIdx)
|
|
4300
|
+
return aIdx - bIdx;
|
|
4301
|
+
}
|
|
4302
|
+
if (a === EMPTY_KEY)
|
|
4303
|
+
return b === EMPTY_KEY ? 0 : -1;
|
|
4304
|
+
if (b === EMPTY_KEY)
|
|
4256
4305
|
return 1;
|
|
4257
4306
|
return a.localeCompare(b);
|
|
4258
4307
|
});
|
|
@@ -4299,9 +4348,12 @@ class GridFilterColumnsMultiSelect {
|
|
|
4299
4348
|
return this.gui;
|
|
4300
4349
|
}
|
|
4301
4350
|
isFilterActive() {
|
|
4302
|
-
return this.selectedValues.size
|
|
4351
|
+
return this.selectedValues.size !== this.allValues.length;
|
|
4303
4352
|
}
|
|
4304
4353
|
doesFilterPass(p) {
|
|
4354
|
+
if (this.selectedValues.size === 0) {
|
|
4355
|
+
return false;
|
|
4356
|
+
}
|
|
4305
4357
|
const field = this.params.colDef.field;
|
|
4306
4358
|
if (!p.data || typeof p.data !== 'object') {
|
|
4307
4359
|
return this.selectedValues.has(EMPTY_KEY);
|
|
@@ -4311,7 +4363,10 @@ class GridFilterColumnsMultiSelect {
|
|
|
4311
4363
|
return this.selectedValues.has(norm);
|
|
4312
4364
|
}
|
|
4313
4365
|
getModel() {
|
|
4314
|
-
|
|
4366
|
+
if (this.selectedValues.size !== this.allValues.length) {
|
|
4367
|
+
return { values: Array.from(this.selectedValues) };
|
|
4368
|
+
}
|
|
4369
|
+
return null;
|
|
4315
4370
|
}
|
|
4316
4371
|
setModel(model) {
|
|
4317
4372
|
this.selectedValues = new Set(model?.values || []);
|
|
@@ -4324,9 +4379,10 @@ class GridFilterColumnsMultiSelect {
|
|
|
4324
4379
|
}
|
|
4325
4380
|
}
|
|
4326
4381
|
}
|
|
4327
|
-
const createCheckboxMultiFilterParams = (labels = {}, labelFormatter) => ({
|
|
4382
|
+
const createCheckboxMultiFilterParams = (labels = {}, labelFormatter, customOrder) => ({
|
|
4328
4383
|
labels: { [EMPTY_KEY]: DEFAULT_EMPTY_LABEL, ...labels },
|
|
4329
4384
|
labelFormatter,
|
|
4385
|
+
customOrder,
|
|
4330
4386
|
});
|
|
4331
4387
|
|
|
4332
4388
|
const GridFilterHeaderIconButton = React.forwardRef(function columnsButton({ icon, title, onClick, buttonProps, disabled = false, size = 'md' }, ref) {
|
|
@@ -4773,6 +4829,7 @@ const textMatch = (text, filter) => {
|
|
|
4773
4829
|
|
|
4774
4830
|
const CancelPromise = () => Promise.resolve(true);
|
|
4775
4831
|
const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick, }) => {
|
|
4832
|
+
const { resetFocusedCellAfterCellEditing } = useGridContext();
|
|
4776
4833
|
const { anchorRef, saving, updateValue, stopEditing } = useGridPopoverContext();
|
|
4777
4834
|
const saveButtonRef = React.useRef(null);
|
|
4778
4835
|
const [isOpen, setOpen] = React.useState(false);
|
|
@@ -4783,6 +4840,7 @@ const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick,
|
|
|
4783
4840
|
if (reason == CloseReason.CANCEL) {
|
|
4784
4841
|
await updateValue(CancelPromise, 0);
|
|
4785
4842
|
stopEditing();
|
|
4843
|
+
resetFocusedCellAfterCellEditing();
|
|
4786
4844
|
return;
|
|
4787
4845
|
}
|
|
4788
4846
|
if (invalid?.()) {
|
|
@@ -4791,8 +4849,9 @@ const useGridPopoverHook = ({ className, save, invalid, dontSaveOnExternalClick,
|
|
|
4791
4849
|
}
|
|
4792
4850
|
if (await updateValue(save ?? (() => Promise.resolve(true)), reason === CloseReason.TAB_FORWARD ? 1 : reason === CloseReason.TAB_BACKWARD ? -1 : 0)) {
|
|
4793
4851
|
stopEditing();
|
|
4852
|
+
resetFocusedCellAfterCellEditing();
|
|
4794
4853
|
}
|
|
4795
|
-
}, [invalid, save, stopEditing, updateValue]);
|
|
4854
|
+
}, [invalid, resetFocusedCellAfterCellEditing, save, stopEditing, updateValue]);
|
|
4796
4855
|
const popoverWrapper = React.useCallback((children) => {
|
|
4797
4856
|
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) => {
|
|
4798
4857
|
// Prevent menu from closing when modals are invoked
|
|
@@ -5161,6 +5220,128 @@ const GridFormEditBearing = (props) => {
|
|
|
5161
5220
|
: props.formatValue(bearingNumberParser(value)), error: bearingStringValidator(value, props.range), helpText: 'Press enter or tab to save' }) }));
|
|
5162
5221
|
};
|
|
5163
5222
|
|
|
5223
|
+
const TextInputValidator = (props, value, data, context) => {
|
|
5224
|
+
if (value == null)
|
|
5225
|
+
return null;
|
|
5226
|
+
// This can happen because subcomponent is invoked without type safety
|
|
5227
|
+
if (typeof value !== 'string') {
|
|
5228
|
+
return 'Value is not a string';
|
|
5229
|
+
}
|
|
5230
|
+
if (props.required && value.trim() == '') {
|
|
5231
|
+
return 'Must not be empty';
|
|
5232
|
+
}
|
|
5233
|
+
if (props.maxLength && value.length > props.maxLength) {
|
|
5234
|
+
return `Must be no longer than ${props.maxLength} characters`;
|
|
5235
|
+
}
|
|
5236
|
+
if (props.maxBytes && stringByteLengthIsInvalid(value, props.maxBytes)) {
|
|
5237
|
+
return `Must be no longer than ${props.maxBytes} bytes`;
|
|
5238
|
+
}
|
|
5239
|
+
const nf = props.numberFormat;
|
|
5240
|
+
if (nf) {
|
|
5241
|
+
if (value != '' && !isFloat(value)) {
|
|
5242
|
+
return `Must be a valid number`;
|
|
5243
|
+
}
|
|
5244
|
+
if (value != '') {
|
|
5245
|
+
const number = parseFloat(value);
|
|
5246
|
+
if (nf.notZero && number === 0) {
|
|
5247
|
+
return `Must not be 0`;
|
|
5248
|
+
}
|
|
5249
|
+
if (nf.gtMin != null && number <= nf.gtMin) {
|
|
5250
|
+
return `Must be greater than ${nf.gtMin.toLocaleString()}`;
|
|
5251
|
+
}
|
|
5252
|
+
if (nf.geMin != null && number < nf.geMin) {
|
|
5253
|
+
return `Must not be less than ${nf.geMin.toLocaleString()}`;
|
|
5254
|
+
}
|
|
5255
|
+
if (nf.ltMax != null && number >= nf.ltMax) {
|
|
5256
|
+
return `Must be less than ${nf.ltMax.toLocaleString()}`;
|
|
5257
|
+
}
|
|
5258
|
+
if (nf.leMax != null && number > nf.leMax) {
|
|
5259
|
+
return `Must not be greater than ${nf.leMax.toLocaleString()}`;
|
|
5260
|
+
}
|
|
5261
|
+
if (nf.precision != null && value != '') {
|
|
5262
|
+
if (parseFloat(number.toPrecision(nf.precision)) != number) {
|
|
5263
|
+
return `Must have no more than ${nf.precision} digits precision`;
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
if (nf.scale != null && value != '') {
|
|
5267
|
+
if (parseFloat(number.toFixed(nf.scale)) != number) {
|
|
5268
|
+
return nf.scale == 0 ? `Must be a whole number` : `Must have no more than ${nf.scale} decimal places`;
|
|
5269
|
+
}
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
}
|
|
5273
|
+
if (props.invalid) {
|
|
5274
|
+
return props.invalid(value, data, context);
|
|
5275
|
+
}
|
|
5276
|
+
return null;
|
|
5277
|
+
};
|
|
5278
|
+
|
|
5279
|
+
const GridFormInlineTextInput = (props) => {
|
|
5280
|
+
const { onSave } = props;
|
|
5281
|
+
const { getSelectedRows, prePopupOps } = useGridContext();
|
|
5282
|
+
const { field, value: initialVale, data } = useGridPopoverContext();
|
|
5283
|
+
const initValue = React.useMemo(() => (initialVale == null ? '' : `${initialVale}`), [initialVale]);
|
|
5284
|
+
const [value, setValue] = React.useState(initValue);
|
|
5285
|
+
const invalid = React.useCallback(() => TextInputValidator(props, value, data, {}), [data, props, value]);
|
|
5286
|
+
React.useEffect(() => {
|
|
5287
|
+
prePopupOps();
|
|
5288
|
+
}, [prePopupOps]);
|
|
5289
|
+
const save = React.useCallback(async () => {
|
|
5290
|
+
if (invalid()) {
|
|
5291
|
+
return false;
|
|
5292
|
+
}
|
|
5293
|
+
const trimmedValue = value.trim();
|
|
5294
|
+
// No change, so don't save
|
|
5295
|
+
if (initValue === trimmedValue) {
|
|
5296
|
+
return true;
|
|
5297
|
+
}
|
|
5298
|
+
if (!onSave) {
|
|
5299
|
+
console.error(`No onSave handler for GridFormInlineTextInput "${String(field)}`);
|
|
5300
|
+
return false;
|
|
5301
|
+
}
|
|
5302
|
+
const selectedRows = getSelectedRows();
|
|
5303
|
+
const selectedRowIds = selectedRows.map((data) => data.id);
|
|
5304
|
+
return onSave({
|
|
5305
|
+
selectedRowIds,
|
|
5306
|
+
selectedRows,
|
|
5307
|
+
value: trimmedValue,
|
|
5308
|
+
});
|
|
5309
|
+
}, [invalid, value, initValue, onSave, getSelectedRows, field]);
|
|
5310
|
+
const inputRef = React.useRef(null);
|
|
5311
|
+
React.useEffect(() => {
|
|
5312
|
+
inputRef.current?.focus();
|
|
5313
|
+
inputRef.current?.select();
|
|
5314
|
+
}, []);
|
|
5315
|
+
const { triggerSave } = useGridPopoverHook({
|
|
5316
|
+
className: props.className,
|
|
5317
|
+
invalid,
|
|
5318
|
+
save,
|
|
5319
|
+
});
|
|
5320
|
+
const tabDirectionRef = React.useRef(CloseReason.BLUR);
|
|
5321
|
+
const tabRecorder = React.useCallback((e) => {
|
|
5322
|
+
if (e.key === 'Tab') {
|
|
5323
|
+
tabDirectionRef.current = e.shiftKey ? CloseReason.TAB_BACKWARD : CloseReason.TAB_FORWARD;
|
|
5324
|
+
e.preventDefault();
|
|
5325
|
+
e.stopPropagation();
|
|
5326
|
+
void triggerSave(tabDirectionRef.current);
|
|
5327
|
+
}
|
|
5328
|
+
}, [triggerSave]);
|
|
5329
|
+
React.useEffect(() => {
|
|
5330
|
+
const input = inputRef.current;
|
|
5331
|
+
input?.addEventListener('keydown', tabRecorder, { capture: true });
|
|
5332
|
+
return () => {
|
|
5333
|
+
input?.removeEventListener('keydown', tabRecorder, { capture: true });
|
|
5334
|
+
};
|
|
5335
|
+
}, [tabRecorder]);
|
|
5336
|
+
return (jsxRuntime.jsx("div", { className: clsx('GridFormInlineTextInput', invalid() && 'GridFormInlineTextInput-error'), title: String(invalid() ?? ''), children: jsxRuntime.jsx("input", { ref: inputRef, type: 'text', value: value, onChange: (e) => setValue(e.target.value), placeholder: props.placeholder ?? 'Type here', onBlur: () => {
|
|
5337
|
+
void triggerSave(CloseReason.BLUR);
|
|
5338
|
+
}, onKeyUp: (e) => {
|
|
5339
|
+
if (e.key === 'Enter') {
|
|
5340
|
+
void triggerSave(CloseReason.BLUR);
|
|
5341
|
+
}
|
|
5342
|
+
} }) }));
|
|
5343
|
+
};
|
|
5344
|
+
|
|
5164
5345
|
const GridFormMessage = (props) => {
|
|
5165
5346
|
const { selectedRows } = useGridPopoverContext();
|
|
5166
5347
|
const [message, setMessage] = React.useState(null);
|
|
@@ -5572,62 +5753,6 @@ const TextAreaInput = (props) => {
|
|
|
5572
5753
|
}, "data-allowtabtosave": props.allowTabToSave, children: props.value }) })] }), jsxRuntime.jsx(FormError, { error: props.error, helpText: props.helpText })] }));
|
|
5573
5754
|
};
|
|
5574
5755
|
|
|
5575
|
-
const TextInputValidator = (props, value, data, context) => {
|
|
5576
|
-
if (value == null)
|
|
5577
|
-
return null;
|
|
5578
|
-
// This can happen because subcomponent is invoked without type safety
|
|
5579
|
-
if (typeof value !== 'string') {
|
|
5580
|
-
return 'Value is not a string';
|
|
5581
|
-
}
|
|
5582
|
-
if (props.required && value.trim() == '') {
|
|
5583
|
-
return 'Must not be empty';
|
|
5584
|
-
}
|
|
5585
|
-
if (props.maxLength && value.length > props.maxLength) {
|
|
5586
|
-
return `Must be no longer than ${props.maxLength} characters`;
|
|
5587
|
-
}
|
|
5588
|
-
if (props.maxBytes && stringByteLengthIsInvalid(value, props.maxBytes)) {
|
|
5589
|
-
return `Must be no longer than ${props.maxBytes} bytes`;
|
|
5590
|
-
}
|
|
5591
|
-
const nf = props.numberFormat;
|
|
5592
|
-
if (nf) {
|
|
5593
|
-
if (value != '' && !isFloat(value)) {
|
|
5594
|
-
return `Must be a valid number`;
|
|
5595
|
-
}
|
|
5596
|
-
if (value != '') {
|
|
5597
|
-
const number = parseFloat(value);
|
|
5598
|
-
if (nf.notZero && number === 0) {
|
|
5599
|
-
return `Must not be 0`;
|
|
5600
|
-
}
|
|
5601
|
-
if (nf.gtMin != null && number <= nf.gtMin) {
|
|
5602
|
-
return `Must be greater than ${nf.gtMin.toLocaleString()}`;
|
|
5603
|
-
}
|
|
5604
|
-
if (nf.geMin != null && number < nf.geMin) {
|
|
5605
|
-
return `Must not be less than ${nf.geMin.toLocaleString()}`;
|
|
5606
|
-
}
|
|
5607
|
-
if (nf.ltMax != null && number >= nf.ltMax) {
|
|
5608
|
-
return `Must be less than ${nf.ltMax.toLocaleString()}`;
|
|
5609
|
-
}
|
|
5610
|
-
if (nf.leMax != null && number > nf.leMax) {
|
|
5611
|
-
return `Must not be greater than ${nf.leMax.toLocaleString()}`;
|
|
5612
|
-
}
|
|
5613
|
-
if (nf.precision != null && value != '') {
|
|
5614
|
-
if (parseFloat(number.toPrecision(nf.precision)) != number) {
|
|
5615
|
-
return `Must have no more than ${nf.precision} digits precision`;
|
|
5616
|
-
}
|
|
5617
|
-
}
|
|
5618
|
-
if (nf.scale != null && value != '') {
|
|
5619
|
-
if (parseFloat(number.toFixed(nf.scale)) != number) {
|
|
5620
|
-
return nf.scale == 0 ? `Must be a whole number` : `Must have no more than ${nf.scale} decimal places`;
|
|
5621
|
-
}
|
|
5622
|
-
}
|
|
5623
|
-
}
|
|
5624
|
-
}
|
|
5625
|
-
if (props.invalid) {
|
|
5626
|
-
return props.invalid(value, data, context);
|
|
5627
|
-
}
|
|
5628
|
-
return null;
|
|
5629
|
-
};
|
|
5630
|
-
|
|
5631
5756
|
const GridFormSubComponentTextArea = (props) => {
|
|
5632
5757
|
const { value, data, setValue, setValid, context } = React.useContext(GridSubComponentContext);
|
|
5633
5758
|
const helpText = props.helpText ?? 'Press tab to save';
|
|
@@ -5806,6 +5931,11 @@ const GridEditBoolean = (colDef, editorProps) => {
|
|
|
5806
5931
|
});
|
|
5807
5932
|
};
|
|
5808
5933
|
|
|
5934
|
+
const GridInlineTextInput = (colDef, params) => GridCell(colDef, {
|
|
5935
|
+
editor: GridFormInlineTextInput,
|
|
5936
|
+
...params,
|
|
5937
|
+
});
|
|
5938
|
+
|
|
5809
5939
|
const GridPopoutEditMultiSelect = (colDef, props) => GridCell(colDef, {
|
|
5810
5940
|
editor: GridFormMultiSelect,
|
|
5811
5941
|
...props,
|
|
@@ -5946,6 +6076,7 @@ const GridContextProvider = (props) => {
|
|
|
5946
6076
|
const [invisibleColumnIds, _setInvisibleColumnIds] = React.useState();
|
|
5947
6077
|
const testId = React.useRef();
|
|
5948
6078
|
const hasExternallySelectedItemsRef = React.useRef(false);
|
|
6079
|
+
const enableMultilineBulkEditRef = React.useRef(false);
|
|
5949
6080
|
const idsBeforeUpdate = React.useRef([]);
|
|
5950
6081
|
const prePopupFocusedCell = React.useRef();
|
|
5951
6082
|
const [externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync] = React.useState(false);
|
|
@@ -6010,8 +6141,9 @@ const GridContextProvider = (props) => {
|
|
|
6010
6141
|
/**
|
|
6011
6142
|
* Set the grid api when the grid is ready.
|
|
6012
6143
|
*/
|
|
6013
|
-
const setApis = React.useCallback((gridApi, hasExternallySelectedItems, dataTestId) => {
|
|
6144
|
+
const setApis = React.useCallback((gridApi, hasExternallySelectedItems, enableMultilineBulkEdit, dataTestId) => {
|
|
6014
6145
|
hasExternallySelectedItemsRef.current = hasExternallySelectedItems;
|
|
6146
|
+
enableMultilineBulkEditRef.current = enableMultilineBulkEdit;
|
|
6015
6147
|
testId.current = dataTestId;
|
|
6016
6148
|
setGridApi(gridApi);
|
|
6017
6149
|
gridApi?.setGridOption('quickFilterText', quickFilter);
|
|
@@ -6156,7 +6288,7 @@ const GridContextProvider = (props) => {
|
|
|
6156
6288
|
if (flash) {
|
|
6157
6289
|
lodashEs.delay(() => {
|
|
6158
6290
|
try {
|
|
6159
|
-
!gridApi.isDestroyed && gridApi.flashCells({ rowNodes });
|
|
6291
|
+
!gridApi.isDestroyed() && gridApi.flashCells({ rowNodes });
|
|
6160
6292
|
}
|
|
6161
6293
|
catch {
|
|
6162
6294
|
// ignore, flash cells sometimes throws errors as nodes have gone out of scope
|
|
@@ -6222,13 +6354,13 @@ const GridContextProvider = (props) => {
|
|
|
6222
6354
|
* Then we size the flexed columns.
|
|
6223
6355
|
*/
|
|
6224
6356
|
const autoSizeColumns = React.useCallback(async ({ skipHeader, colIds, userSizedColIds } = {}) => {
|
|
6225
|
-
if (!gridApi || !gridApi.getColumnState()) {
|
|
6357
|
+
if (!gridApi || gridApi.isDestroyed() || !gridApi.getColumnState()) {
|
|
6226
6358
|
return null;
|
|
6227
6359
|
}
|
|
6228
6360
|
try {
|
|
6229
6361
|
const colIdsSet = colIds instanceof Set ? colIds : new Set(colIds);
|
|
6230
6362
|
const getVisibleColStates = () => {
|
|
6231
|
-
const colStates = gridApi.getColumnState();
|
|
6363
|
+
const colStates = gridApi.getColumnState() ?? [];
|
|
6232
6364
|
return colStates.filter((colState) => {
|
|
6233
6365
|
const colId = colState.colId;
|
|
6234
6366
|
return (lodashEs.isEmpty(colIdsSet) || colIdsSet.has(colId)) && !userSizedColIds?.has(colId);
|
|
@@ -6288,9 +6420,11 @@ const GridContextProvider = (props) => {
|
|
|
6288
6420
|
if (!gridApi || gridApi.isDestroyed() || startCellEditingInProgressRef.current) {
|
|
6289
6421
|
return;
|
|
6290
6422
|
}
|
|
6291
|
-
|
|
6292
|
-
|
|
6293
|
-
|
|
6423
|
+
const cellToFocus = prePopupFocusedCell.current;
|
|
6424
|
+
if (cellToFocus) {
|
|
6425
|
+
lodashEs.defer(() => {
|
|
6426
|
+
gridApi.setFocusedCell(cellToFocus.rowIndex, cellToFocus.column);
|
|
6427
|
+
});
|
|
6294
6428
|
}
|
|
6295
6429
|
}, [gridApi]);
|
|
6296
6430
|
// waitForExternallySelectedItemsToBeInSync can't use the state as it won't be updated during function execution
|
|
@@ -6356,9 +6490,8 @@ const GridContextProvider = (props) => {
|
|
|
6356
6490
|
}, [anyUpdating, gridApi, prePopupOps, waitForExternallySelectedItemsToBeInSync]);
|
|
6357
6491
|
const bulkEditingCompleteCallbackRef = React.useRef();
|
|
6358
6492
|
const onBulkEditingComplete = React.useCallback(async () => {
|
|
6359
|
-
resetFocusedCellAfterCellEditing();
|
|
6360
6493
|
await bulkEditingCompleteCallbackRef.current?.();
|
|
6361
|
-
}, [
|
|
6494
|
+
}, []);
|
|
6362
6495
|
const setOnBulkEditingComplete = React.useCallback((cellEditingCompleteCallback) => {
|
|
6363
6496
|
bulkEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
|
|
6364
6497
|
}, []);
|
|
@@ -6398,10 +6531,18 @@ const GridContextProvider = (props) => {
|
|
|
6398
6531
|
return true;
|
|
6399
6532
|
}
|
|
6400
6533
|
const postRow = gridApi.getFocusedCell();
|
|
6401
|
-
if (
|
|
6402
|
-
//
|
|
6403
|
-
|
|
6404
|
-
|
|
6534
|
+
if (enableMultilineBulkEditRef.current) {
|
|
6535
|
+
// Last cell in grid, nowhere to tab
|
|
6536
|
+
if (preRow?.rowIndex === postRow?.rowIndex && preRow?.column === postRow?.column) {
|
|
6537
|
+
break;
|
|
6538
|
+
}
|
|
6539
|
+
}
|
|
6540
|
+
else {
|
|
6541
|
+
if (preRow?.rowIndex !== postRow?.rowIndex || preRow?.column === postRow?.column) {
|
|
6542
|
+
// We didn't find an editable cell in the same row, or the cell column didn't change
|
|
6543
|
+
// implying it was start/end of grid
|
|
6544
|
+
break;
|
|
6545
|
+
}
|
|
6405
6546
|
}
|
|
6406
6547
|
if (focusedCellIsEditable()) {
|
|
6407
6548
|
const focusedCell = gridApi.getFocusedCell();
|
|
@@ -6785,6 +6926,7 @@ exports.GridFilterQuick = GridFilterQuick;
|
|
|
6785
6926
|
exports.GridFilters = GridFilters;
|
|
6786
6927
|
exports.GridFormDropDown = GridFormDropDown;
|
|
6787
6928
|
exports.GridFormEditBearing = GridFormEditBearing;
|
|
6929
|
+
exports.GridFormInlineTextInput = GridFormInlineTextInput;
|
|
6788
6930
|
exports.GridFormMessage = GridFormMessage;
|
|
6789
6931
|
exports.GridFormMultiSelect = GridFormMultiSelect;
|
|
6790
6932
|
exports.GridFormMultiSelectGrid = GridFormMultiSelectGrid;
|
|
@@ -6794,6 +6936,7 @@ exports.GridFormSubComponentTextInput = GridFormSubComponentTextInput;
|
|
|
6794
6936
|
exports.GridFormTextArea = GridFormTextArea;
|
|
6795
6937
|
exports.GridFormTextInput = GridFormTextInput;
|
|
6796
6938
|
exports.GridIcon = GridIcon;
|
|
6939
|
+
exports.GridInlineTextInput = GridInlineTextInput;
|
|
6797
6940
|
exports.GridLoadableCell = GridLoadableCell;
|
|
6798
6941
|
exports.GridNoRowsOverlay = GridNoRowsOverlay;
|
|
6799
6942
|
exports.GridNoRowsOverlayFr = GridNoRowsOverlayFr;
|