@linzjs/step-ag-grid 29.1.6 → 29.2.1
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/Grid.d.ts +2 -1
- package/dist/step-ag-grid.cjs +56 -18
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +56 -18
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +2 -1
- package/src/components/Grid.tsx +66 -17
- package/src/contexts/GridContextProvider.tsx +3 -1
- package/src/stories/grid/gridAutosize/ShowPanelResizingAgGrid/ShowPanelResizingAgGrid.stories.tsx +28 -0
- package/src/stories/grid/gridAutosize/ShowPanelResizingAgGrid/ShowPanelResizingStepAgGrid.tsx +169 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@linzjs/step-ag-grid",
|
|
3
3
|
"repository": "github:linz/step-ag-grid.git",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "29.1
|
|
5
|
+
"version": "29.2.1",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"aggrid",
|
|
8
8
|
"ag-grid",
|
|
@@ -83,6 +83,7 @@
|
|
|
83
83
|
"@chromatic-com/storybook": "^4.1.1",
|
|
84
84
|
"@linzjs/lui": "^23.11.1",
|
|
85
85
|
"@linzjs/style": "^5.4.0",
|
|
86
|
+
"@linzjs/windows": "^5.5.1",
|
|
86
87
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
87
88
|
"@rollup/plugin-json": "^6.1.0",
|
|
88
89
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
package/src/components/Grid.tsx
CHANGED
|
@@ -14,6 +14,8 @@ import {
|
|
|
14
14
|
GetRowIdParams,
|
|
15
15
|
GridOptions,
|
|
16
16
|
GridReadyEvent,
|
|
17
|
+
GridSizeChangedEvent,
|
|
18
|
+
IColumnLimit,
|
|
17
19
|
ModelUpdatedEvent,
|
|
18
20
|
ModuleRegistry,
|
|
19
21
|
RowClickedEvent,
|
|
@@ -124,6 +126,7 @@ export interface GridProps<TData extends GridBaseRow = GridBaseRow> {
|
|
|
124
126
|
pinnedBottomRowData?: GridOptions['pinnedBottomRowData'];
|
|
125
127
|
onRowClicked?: (event: RowClickedEvent) => void;
|
|
126
128
|
onRowDoubleClicked?: (event: RowDoubleClickedEvent) => void;
|
|
129
|
+
allowResizeInStorybook?: boolean;
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
/**
|
|
@@ -142,6 +145,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
142
145
|
rowData,
|
|
143
146
|
rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40,
|
|
144
147
|
selectable,
|
|
148
|
+
allowResizeInStorybook,
|
|
145
149
|
onCellFocused: paramsOnCellFocused,
|
|
146
150
|
...params
|
|
147
151
|
}: GridProps<TData>): ReactElement => {
|
|
@@ -204,7 +208,11 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
204
208
|
|
|
205
209
|
const skipHeader = sizeColumns === 'auto-skip-headers' && gridRendered === 'rows-visible';
|
|
206
210
|
if (sizeColumns === 'auto' || skipHeader) {
|
|
207
|
-
const result = autoSizeColumns({
|
|
211
|
+
const result = autoSizeColumns({
|
|
212
|
+
skipHeader,
|
|
213
|
+
userSizedColIds: new Set(userSizedColIds.current.keys()),
|
|
214
|
+
includeFlex: true,
|
|
215
|
+
});
|
|
208
216
|
if (!result) {
|
|
209
217
|
needsAutoSize.current = true;
|
|
210
218
|
return;
|
|
@@ -238,11 +246,29 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
238
246
|
}, [autoSizeColumns, gridRenderState, params, rowData, sizeColumns, sizeColumnsToFit]);
|
|
239
247
|
|
|
240
248
|
const lastOwnerDocumentRef = useRef<Document>();
|
|
249
|
+
const wasVisibleRef = useRef(false);
|
|
241
250
|
|
|
242
251
|
/**
|
|
243
252
|
* Auto-size windows that had deferred auto-size
|
|
253
|
+
* Reset focus if panel went from invisible to visible.
|
|
244
254
|
*/
|
|
245
255
|
useInterval(() => {
|
|
256
|
+
// If grid has become visible after previously being hidden, then refocus the last focused cell.
|
|
257
|
+
const visible = !!gridDivRef.current?.checkVisibility();
|
|
258
|
+
if (visible && !wasVisibleRef.current) {
|
|
259
|
+
wasVisibleRef.current = true;
|
|
260
|
+
const el = (window as any).__stepaggrid_lastfocuseventtarget;
|
|
261
|
+
if (el) {
|
|
262
|
+
// Setting this to null will cause a new refocus event
|
|
263
|
+
(window as any).__stepaggrid_lastfocuseventtarget = null;
|
|
264
|
+
// Check element is still part of document
|
|
265
|
+
if (el.checkVisibility()) {
|
|
266
|
+
el.focus();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
wasVisibleRef.current = visible;
|
|
271
|
+
|
|
246
272
|
// Check if window has been popped out and needs resize
|
|
247
273
|
const currentDocument = gridDivRef.current?.ownerDocument;
|
|
248
274
|
if (currentDocument !== lastOwnerDocumentRef.current) {
|
|
@@ -407,7 +433,11 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
407
433
|
|
|
408
434
|
const skipHeader = sizeColumns === 'auto-skip-headers';
|
|
409
435
|
if (hasSetContentSize.current) {
|
|
410
|
-
autoSizeColumns({
|
|
436
|
+
autoSizeColumns({
|
|
437
|
+
skipHeader,
|
|
438
|
+
userSizedColIds: new Set(userSizedColIds.current.keys()),
|
|
439
|
+
colIds: colIdsEdited.current,
|
|
440
|
+
});
|
|
411
441
|
}
|
|
412
442
|
colIdsEdited.current.clear();
|
|
413
443
|
}, [autoSizeColumns, rowData?.length, setInitialContentSize, sizeColumns, updatedDep, updatingCols]);
|
|
@@ -525,7 +555,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
525
555
|
if (hasSetContentSize.current) {
|
|
526
556
|
autoSizeColumns({
|
|
527
557
|
skipHeader,
|
|
528
|
-
userSizedColIds: userSizedColIds.current,
|
|
558
|
+
userSizedColIds: new Set(userSizedColIds.current.keys()),
|
|
529
559
|
colIds: colIdsEdited.current,
|
|
530
560
|
});
|
|
531
561
|
}
|
|
@@ -555,26 +585,43 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
555
585
|
/**
|
|
556
586
|
* Resize columns to fit if required on window/container resize
|
|
557
587
|
*/
|
|
558
|
-
const onGridSizeChanged = useCallback(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
588
|
+
const onGridSizeChanged = useCallback(
|
|
589
|
+
(event: GridSizeChangedEvent<TData>) => {
|
|
590
|
+
if (sizeColumns !== 'none' && (!(window as any).__STORYBOOK_PREVIEW__ || allowResizeInStorybook)) {
|
|
591
|
+
const columnLimits = [
|
|
592
|
+
...userSizedColIds.current.entries().map(
|
|
593
|
+
([c, w]): IColumnLimit => ({
|
|
594
|
+
key: c,
|
|
595
|
+
minWidth: w,
|
|
596
|
+
}),
|
|
597
|
+
),
|
|
598
|
+
];
|
|
599
|
+
event.api.sizeColumnsToFit({ columnLimits });
|
|
600
|
+
}
|
|
601
|
+
},
|
|
602
|
+
[allowResizeInStorybook, sizeColumns],
|
|
603
|
+
);
|
|
563
604
|
|
|
564
605
|
/**
|
|
565
606
|
* Set of column I'd's that are prevented from auto-sizing as they are user set
|
|
566
607
|
*/
|
|
567
|
-
const userSizedColIds = useRef(new
|
|
608
|
+
const userSizedColIds = useRef(new Map<string, number>());
|
|
568
609
|
|
|
569
610
|
/**
|
|
570
611
|
* Lock/unlock column width on user edit/reset.
|
|
571
612
|
*/
|
|
572
613
|
const onColumnResized = useCallback((e: ColumnResizedEvent) => {
|
|
573
614
|
const colId = e.column?.getColId();
|
|
574
|
-
if (colId == null)
|
|
615
|
+
if (colId == null) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const width = e.column?.getActualWidth();
|
|
619
|
+
if (width == null) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
575
622
|
switch (e.source) {
|
|
576
|
-
case '
|
|
577
|
-
userSizedColIds.current.
|
|
623
|
+
case 'uiColumnResized':
|
|
624
|
+
userSizedColIds.current.set(colId, width);
|
|
578
625
|
break;
|
|
579
626
|
case 'autosizeColumns':
|
|
580
627
|
userSizedColIds.current.delete(colId);
|
|
@@ -625,7 +672,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
625
672
|
|
|
626
673
|
const onCellFocused = useCallback(
|
|
627
674
|
(event: CellFocusedEvent<TData>) => {
|
|
628
|
-
if (
|
|
675
|
+
if (event.rowIndex == null) {
|
|
629
676
|
return;
|
|
630
677
|
}
|
|
631
678
|
const api = event.api;
|
|
@@ -639,15 +686,17 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
639
686
|
if (!colDef || typeof colDef === 'string') {
|
|
640
687
|
return;
|
|
641
688
|
}
|
|
642
|
-
// Prevent repeated callbacks to cell focus when
|
|
689
|
+
// Prevent repeated callbacks to cell focus when focus didn't change
|
|
643
690
|
const { sourceEvent } = event;
|
|
644
691
|
if (sourceEvent) {
|
|
645
|
-
|
|
692
|
+
const cell = (sourceEvent.target as Element | undefined)?.closest?.('.ag-cell') ?? null;
|
|
693
|
+
if ((window as any).__stepaggrid_lastfocuseventtarget === cell) {
|
|
646
694
|
return;
|
|
647
695
|
}
|
|
648
|
-
(window as any).__stepaggrid_lastfocuseventtarget =
|
|
696
|
+
(window as any).__stepaggrid_lastfocuseventtarget = cell;
|
|
649
697
|
}
|
|
650
|
-
|
|
698
|
+
|
|
699
|
+
paramsOnCellFocused?.({ colDef, data });
|
|
651
700
|
},
|
|
652
701
|
[paramsOnCellFocused],
|
|
653
702
|
);
|
|
@@ -424,7 +424,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
|
|
|
424
424
|
*/
|
|
425
425
|
const autoSizeColumns = useCallback(
|
|
426
426
|
({ skipHeader, colIds, userSizedColIds, includeFlex }: AutoSizeColumnsProps = {}): AutoSizeColumnsResult => {
|
|
427
|
-
if (!gridApi || !gridApi.getColumnState())
|
|
427
|
+
if (!gridApi || !gridApi.getColumnState()) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
428
430
|
const colIdsSet = colIds instanceof Set ? colIds : new Set(colIds);
|
|
429
431
|
const colsToResize = gridApi.getColumnState()?.filter?.((colState) => {
|
|
430
432
|
const colId = colState.colId;
|
package/src/stories/grid/gridAutosize/ShowPanelResizingAgGrid/ShowPanelResizingAgGrid.stories.tsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PanelsContextProvider } from '@linzjs/windows';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
3
|
+
|
|
4
|
+
import { TestShowPanelResizingAgGrid } from './ShowPanelResizingStepAgGrid';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof TestShowPanelResizingAgGrid> = {
|
|
7
|
+
title: 'Components/Panel',
|
|
8
|
+
component: TestShowPanelResizingAgGrid,
|
|
9
|
+
argTypes: {
|
|
10
|
+
backgroundColor: { control: 'color' },
|
|
11
|
+
},
|
|
12
|
+
decorators: [
|
|
13
|
+
(Story) => (
|
|
14
|
+
<div>
|
|
15
|
+
<PanelsContextProvider baseZIndex={500}>
|
|
16
|
+
<Story />
|
|
17
|
+
</PanelsContextProvider>
|
|
18
|
+
</div>
|
|
19
|
+
),
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
type Story = StoryObj<typeof meta>;
|
|
25
|
+
|
|
26
|
+
export const PanelResizing: Story = {
|
|
27
|
+
args: {},
|
|
28
|
+
};
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
// import '../story.scss';
|
|
2
|
+
import '@linzjs/lui/dist/scss/base.scss';
|
|
3
|
+
import '../../../../styles/Grid.scss';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
OpenPanelButton,
|
|
7
|
+
Panel,
|
|
8
|
+
PanelContent,
|
|
9
|
+
PanelContext,
|
|
10
|
+
PanelHeader,
|
|
11
|
+
PanelsContextProvider,
|
|
12
|
+
} from '@linzjs/windows';
|
|
13
|
+
import { useContext, useMemo, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
ColDefT,
|
|
17
|
+
Grid,
|
|
18
|
+
GridCell,
|
|
19
|
+
GridContextProvider,
|
|
20
|
+
GridIcon,
|
|
21
|
+
GridPopoverMenu,
|
|
22
|
+
GridPopoverMessage,
|
|
23
|
+
GridUpdatingContextProvider,
|
|
24
|
+
GridWrapper,
|
|
25
|
+
} from '../../../../../src';
|
|
26
|
+
|
|
27
|
+
// #Example: Panel Context Provider
|
|
28
|
+
// Don't forget to add a PanelContextProvider at the root of your project
|
|
29
|
+
export const App = () => (
|
|
30
|
+
<PanelsContextProvider baseZIndex={500}>
|
|
31
|
+
<div>...the rest of your app...</div>
|
|
32
|
+
</PanelsContextProvider>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// #Example: Panel Component
|
|
36
|
+
export interface TestPanelProps {
|
|
37
|
+
data: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const TestPanelResizing = ({ data }: TestPanelProps) => {
|
|
41
|
+
return (
|
|
42
|
+
<Panel title={`Panel resizing demo ${data}`} size={{ width: 320, height: 400 }} className={'WindowPanel-blue'}>
|
|
43
|
+
<PanelHeader />
|
|
44
|
+
<PanelContent>
|
|
45
|
+
<PanelContentsWithResize />
|
|
46
|
+
</PanelContent>
|
|
47
|
+
</Panel>
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// #Example: Panel Invocation
|
|
52
|
+
export const TestShowPanelResizingAgGrid = () => (
|
|
53
|
+
<>
|
|
54
|
+
<OpenPanelButton buttonText={'TestPanel resizing 1'} componentFn={() => <TestPanelResizing data={1} />} />{' '}
|
|
55
|
+
<OpenPanelButton buttonText={'TestPanel resizing 2'} componentFn={() => <TestPanelResizing data={2} />} />
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/* exclude */
|
|
60
|
+
interface ITestRow {
|
|
61
|
+
id: number;
|
|
62
|
+
position: string;
|
|
63
|
+
age: number;
|
|
64
|
+
desc: string;
|
|
65
|
+
dd: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* exclude */
|
|
69
|
+
|
|
70
|
+
// #Example: Resizing panel to content after load
|
|
71
|
+
// Note: Resize can only be used from within the panel content.
|
|
72
|
+
export const PanelContentsWithResize = () => {
|
|
73
|
+
// This is the first important bit
|
|
74
|
+
const { resizePanel } = useContext(PanelContext);
|
|
75
|
+
|
|
76
|
+
const columnDefs: ColDefT<ITestRow>[] = useMemo(
|
|
77
|
+
() => [
|
|
78
|
+
/* Your grid ColDefs */
|
|
79
|
+
/* exclude */
|
|
80
|
+
GridCell({
|
|
81
|
+
field: 'id',
|
|
82
|
+
headerName: 'Id',
|
|
83
|
+
lockVisible: true,
|
|
84
|
+
}),
|
|
85
|
+
GridCell({
|
|
86
|
+
field: 'position',
|
|
87
|
+
headerName: 'Position',
|
|
88
|
+
cellRendererParams: {
|
|
89
|
+
warning: (props) => props.value === 'Tester' && 'Testers are testing',
|
|
90
|
+
info: (props) => props.value === 'Developer' && 'Developers are awesome',
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
93
|
+
GridCell({
|
|
94
|
+
field: 'age',
|
|
95
|
+
headerName: 'Age',
|
|
96
|
+
}),
|
|
97
|
+
GridCell({
|
|
98
|
+
field: 'desc',
|
|
99
|
+
headerName: 'Description',
|
|
100
|
+
flex: 1,
|
|
101
|
+
}),
|
|
102
|
+
GridPopoverMessage(
|
|
103
|
+
{
|
|
104
|
+
headerName: 'Popout message',
|
|
105
|
+
cellRenderer: () => <>Single Click me!</>,
|
|
106
|
+
exportable: false,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
multiEdit: true,
|
|
110
|
+
editorParams: {
|
|
111
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
112
|
+
message: async (selectedRows): Promise<string> => {
|
|
113
|
+
return `There are ${selectedRows.length} row(s) selected`;
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
),
|
|
118
|
+
GridCell({
|
|
119
|
+
headerName: 'Custom edit',
|
|
120
|
+
editable: true,
|
|
121
|
+
valueFormatter: () => 'Press E',
|
|
122
|
+
cellRendererParams: {
|
|
123
|
+
rightHoverElement: (
|
|
124
|
+
<GridIcon icon={'ic_launch_modal'} title={'Title text'} className={'GridCell-editableIcon'} />
|
|
125
|
+
),
|
|
126
|
+
editAction: (selectedRows) => {
|
|
127
|
+
alert(`Custom edit ${selectedRows.map((r) => r.id).join()} rowId(s) selected`);
|
|
128
|
+
},
|
|
129
|
+
shortcutKeys: {
|
|
130
|
+
e: () => {
|
|
131
|
+
alert('Hi');
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
}),
|
|
136
|
+
GridPopoverMenu(
|
|
137
|
+
{},
|
|
138
|
+
{
|
|
139
|
+
multiEdit: true,
|
|
140
|
+
editorParams: {
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
142
|
+
options: async () => [],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
),
|
|
146
|
+
/* exclude */
|
|
147
|
+
],
|
|
148
|
+
[],
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const [rowData] = useState([
|
|
152
|
+
/* Your grid row data */
|
|
153
|
+
/* exclude */
|
|
154
|
+
{ id: 1000, position: 'Tester', age: 30, desc: 'Tests application', dd: '1' },
|
|
155
|
+
{ id: 1001, position: 'Developer', age: 12, desc: 'Develops application', dd: '2' },
|
|
156
|
+
{ id: 1002, position: 'Manager', age: 65, desc: 'Manages', dd: '3' },
|
|
157
|
+
/* exclude */
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<GridUpdatingContextProvider>
|
|
162
|
+
<GridContextProvider>
|
|
163
|
+
<GridWrapper>
|
|
164
|
+
<Grid columnDefs={columnDefs} rowData={rowData} onContentSize={resizePanel} allowResizeInStorybook={true} />
|
|
165
|
+
</GridWrapper>
|
|
166
|
+
</GridContextProvider>
|
|
167
|
+
</GridUpdatingContextProvider>
|
|
168
|
+
);
|
|
169
|
+
};
|