@linzjs/step-ag-grid 29.13.0 → 29.14.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/index.css +26 -2
- package/dist/src/components/Grid.d.ts +36 -61
- package/dist/src/components/GridRangeSelectContextMenu.d.ts +10 -0
- package/dist/src/components/gridForm/GridFormDropDown.d.ts +1 -1
- package/dist/src/components/gridForm/GridFormPopoverMenu.d.ts +2 -1
- package/dist/src/components/gridHook/useGridContextMenu.d.ts +12 -7
- package/dist/src/components/gridHook/useGridCopy.d.ts +15 -0
- package/dist/src/components/gridHook/useGridCopySettings.d.ts +11 -0
- package/dist/src/components/gridHook/useGridRangeSelection.d.ts +25 -0
- package/dist/src/components/gridPopoverEdit/GridPopoverEditBearing.d.ts +2 -0
- package/dist/src/components/types.d.ts +1 -0
- package/dist/src/contexts/GridContext.d.ts +1 -0
- package/dist/src/lui/timeoutHook.d.ts +0 -6
- package/dist/src/lui/tsUtils.d.ts +5 -0
- package/dist/src/utils/__tests__/random.ts +19 -0
- package/dist/src/utils/util.d.ts +1 -0
- package/dist/step-ag-grid.cjs +560 -79
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +561 -82
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Grid.tsx +249 -179
- package/src/components/GridRangeSelectContextMenu.tsx +73 -0
- package/src/components/gridForm/GridFormDropDown.tsx +1 -3
- package/src/components/gridForm/GridFormPopoverMenu.tsx +2 -1
- package/src/components/gridHook/useGridContextMenu.tsx +22 -9
- package/src/components/gridHook/useGridCopy.ts +279 -0
- package/src/components/gridHook/useGridCopySettings.ts +28 -0
- package/src/components/gridHook/useGridRangeSelection.ts +235 -0
- package/src/components/gridPopoverEdit/GridPopoverEditBearing.ts +3 -0
- package/src/components/types.ts +2 -0
- package/src/contexts/GridContext.tsx +2 -0
- package/src/contexts/GridContextProvider.tsx +5 -2
- package/src/lui/timeoutHook.tsx +0 -19
- package/src/lui/tsUtils.ts +8 -0
- package/src/stories/grid/GridCopy.stories.tsx +175 -0
- package/src/stories/grid/GridPopoverEditBearing.stories.tsx +4 -4
- package/src/stories/grid/GridReadOnly.stories.tsx +1 -0
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +2 -2
- package/src/styles/ContextMenu.scss +61 -0
- package/src/styles/Grid.scss +26 -2
- package/src/utils/__tests__/random.ts +19 -0
- package/src/utils/bearing.ts +2 -2
- package/src/utils/util.ts +2 -0
package/src/lui/timeoutHook.tsx
CHANGED
|
@@ -38,22 +38,3 @@ export const useTimeoutHook = () => {
|
|
|
38
38
|
|
|
39
39
|
return invoke;
|
|
40
40
|
};
|
|
41
|
-
|
|
42
|
-
interface IntervalHookProps {
|
|
43
|
-
timeoutMs: number;
|
|
44
|
-
callback: () => void;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export const useIntervalHook = ({ callback, timeoutMs }: IntervalHookProps) => {
|
|
48
|
-
const callbackRef = useRef(callback);
|
|
49
|
-
callbackRef.current = callback;
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
const interval = setInterval(() => {
|
|
53
|
-
callbackRef.current && callbackRef.current();
|
|
54
|
-
}, timeoutMs);
|
|
55
|
-
return () => {
|
|
56
|
-
clearInterval(interval);
|
|
57
|
-
};
|
|
58
|
-
}, [timeoutMs]);
|
|
59
|
-
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type KeysOfType<TObject, TValue> = {
|
|
2
|
+
[K in keyof TObject]: TObject[K] extends TValue ? K : never;
|
|
3
|
+
}[keyof TObject];
|
|
4
|
+
|
|
5
|
+
export const typedKeys = <T extends object>(obj: T): (keyof T)[] => Object.keys(obj) as (keyof T)[];
|
|
6
|
+
|
|
7
|
+
export const typedEntries = <T extends object>(obj: T): { [K in keyof T]-?: [K, T[K]] }[keyof T][] =>
|
|
8
|
+
Object.entries(obj) as { [K in keyof T]-?: [K, T[K]] }[keyof T][];
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import '../../styles/GridTheme.scss';
|
|
2
|
+
import '../../styles/index.scss';
|
|
3
|
+
import '@linzjs/lui/dist/scss/base.scss';
|
|
4
|
+
import '@linzjs/lui/dist/fonts';
|
|
5
|
+
|
|
6
|
+
import { LuiMessagingContextProvider } from '@linzjs/lui';
|
|
7
|
+
import { Meta, StoryFn } from '@storybook/react-vite';
|
|
8
|
+
import { useMemo, useState } from 'react';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ColDefT,
|
|
12
|
+
Grid,
|
|
13
|
+
GridCell,
|
|
14
|
+
GridCellBearingValueFormatter,
|
|
15
|
+
GridContextProvider,
|
|
16
|
+
GridFilterQuick,
|
|
17
|
+
GridFilters,
|
|
18
|
+
GridPopoverMenu,
|
|
19
|
+
GridProps,
|
|
20
|
+
GridUpdatingContextProvider,
|
|
21
|
+
GridWrapper,
|
|
22
|
+
} from '../..';
|
|
23
|
+
import { GridFilterColumnsToggle, GridFilterDownloadCsvButton } from '../../components';
|
|
24
|
+
import { GridCellFiller } from '../../components/GridCellFiller';
|
|
25
|
+
import { SeededRandomForTests } from '../../utils/__tests__/random';
|
|
26
|
+
import { waitForGridReady } from '../../utils/__tests__/storybookTestUtil';
|
|
27
|
+
|
|
28
|
+
export default {
|
|
29
|
+
title: 'Components / Grids',
|
|
30
|
+
component: Grid,
|
|
31
|
+
args: {
|
|
32
|
+
quickFilter: true,
|
|
33
|
+
quickFilterValue: '',
|
|
34
|
+
quickFilterPlaceholder: 'Quick filter...',
|
|
35
|
+
selectable: false,
|
|
36
|
+
rowSelection: 'multiple',
|
|
37
|
+
}, // Storybook hangs otherwise
|
|
38
|
+
parameters: {
|
|
39
|
+
docs: {
|
|
40
|
+
source: {
|
|
41
|
+
type: 'code',
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
decorators: [
|
|
46
|
+
(Story) => (
|
|
47
|
+
<LuiMessagingContextProvider version="v2">
|
|
48
|
+
<div style={{ maxWidth: 1024, height: '80vh', display: 'flex', flexDirection: 'column' }}>
|
|
49
|
+
<GridUpdatingContextProvider>
|
|
50
|
+
<GridContextProvider>
|
|
51
|
+
<Story />
|
|
52
|
+
</GridContextProvider>
|
|
53
|
+
</GridUpdatingContextProvider>
|
|
54
|
+
</div>
|
|
55
|
+
</LuiMessagingContextProvider>
|
|
56
|
+
),
|
|
57
|
+
],
|
|
58
|
+
} as Meta<typeof Grid>;
|
|
59
|
+
|
|
60
|
+
interface ITestRow {
|
|
61
|
+
id: number;
|
|
62
|
+
position?: string;
|
|
63
|
+
age: number;
|
|
64
|
+
height: string;
|
|
65
|
+
bearing: string | number | null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const GridCopyTemplate: StoryFn<typeof Grid<ITestRow>> = (props: GridProps<ITestRow>) => {
|
|
69
|
+
const [externalSelectedIds, setExternalSelectedIds] = useState<number[]>([]);
|
|
70
|
+
const columnDefs: ColDefT<ITestRow>[] = useMemo(
|
|
71
|
+
() => [
|
|
72
|
+
GridCell({
|
|
73
|
+
field: 'id',
|
|
74
|
+
headerName: 'Id',
|
|
75
|
+
lockVisible: true,
|
|
76
|
+
}),
|
|
77
|
+
GridCell<ITestRow, ITestRow['position']>({
|
|
78
|
+
field: 'position',
|
|
79
|
+
headerName: 'Position',
|
|
80
|
+
cellRendererParams: {
|
|
81
|
+
error: ({ value }) => value === 'Manager' && 'Managers need management',
|
|
82
|
+
warning: ({ value }) => value === 'Tester' && 'Testers are testing',
|
|
83
|
+
info: ({ value }) => value === 'Developer' && 'Developers are awesome',
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
{
|
|
87
|
+
headerName: 'Metrics',
|
|
88
|
+
marryChildren: true,
|
|
89
|
+
children: [
|
|
90
|
+
GridCell<ITestRow, ITestRow['age']>({
|
|
91
|
+
field: 'age',
|
|
92
|
+
headerName: 'Age',
|
|
93
|
+
}),
|
|
94
|
+
GridCell<ITestRow, ITestRow['height']>({
|
|
95
|
+
field: 'height',
|
|
96
|
+
headerName: 'Height',
|
|
97
|
+
}),
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
GridCell({
|
|
101
|
+
field: 'bearing',
|
|
102
|
+
headerName: 'Bearing',
|
|
103
|
+
valueFormatter: GridCellBearingValueFormatter,
|
|
104
|
+
}),
|
|
105
|
+
GridCellFiller(),
|
|
106
|
+
GridPopoverMenu(
|
|
107
|
+
{},
|
|
108
|
+
{
|
|
109
|
+
editorParams: {
|
|
110
|
+
options: () => [
|
|
111
|
+
{
|
|
112
|
+
label: 'Test menu',
|
|
113
|
+
action: () => {},
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
),
|
|
119
|
+
],
|
|
120
|
+
[],
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
const [rowData] = useState<ITestRow[]>(() => {
|
|
124
|
+
const random = new SeededRandomForTests(1000);
|
|
125
|
+
let id = 1000;
|
|
126
|
+
const positions = [
|
|
127
|
+
undefined,
|
|
128
|
+
'Tester',
|
|
129
|
+
'Developer',
|
|
130
|
+
'Lawyer',
|
|
131
|
+
'Barrista """',
|
|
132
|
+
'Manager',
|
|
133
|
+
'CEO',
|
|
134
|
+
'CTO',
|
|
135
|
+
'Architect',
|
|
136
|
+
];
|
|
137
|
+
const result: ITestRow[] = [];
|
|
138
|
+
for (let i = 0; i < 1000; i++) {
|
|
139
|
+
result.push({
|
|
140
|
+
id: id++,
|
|
141
|
+
position: random.fromArray(positions),
|
|
142
|
+
age: 30,
|
|
143
|
+
height: `${random.next(3) + 3}'${random.next(12)}"`,
|
|
144
|
+
bearing: Math.random() * 360,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<GridWrapper>
|
|
152
|
+
<GridFilters>
|
|
153
|
+
<GridFilterQuick />
|
|
154
|
+
<GridFilterColumnsToggle />
|
|
155
|
+
<GridFilterDownloadCsvButton fileName={'readOnlyGrid'} />
|
|
156
|
+
</GridFilters>
|
|
157
|
+
<Grid
|
|
158
|
+
data-testid={'readonly'}
|
|
159
|
+
{...props}
|
|
160
|
+
enableRangeSelection={true}
|
|
161
|
+
selectable={true}
|
|
162
|
+
enableClickSelection={true}
|
|
163
|
+
enableSelectionWithoutKeys={true}
|
|
164
|
+
autoSelectFirstRow={true}
|
|
165
|
+
externalSelectedIds={externalSelectedIds}
|
|
166
|
+
setExternalSelectedIds={setExternalSelectedIds}
|
|
167
|
+
columnDefs={columnDefs}
|
|
168
|
+
rowData={rowData}
|
|
169
|
+
/>
|
|
170
|
+
</GridWrapper>
|
|
171
|
+
);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
export const GridCopy = GridCopyTemplate.bind({});
|
|
175
|
+
GridCopy.play = waitForGridReady;
|
|
@@ -51,8 +51,8 @@ interface ITestRow {
|
|
|
51
51
|
bearing: string | number | null;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const GridPopoverEditBearingTemplate: StoryFn<typeof Grid
|
|
55
|
-
const [
|
|
54
|
+
const GridPopoverEditBearingTemplate: StoryFn<typeof Grid<ITestRow>> = (props: GridProps<ITestRow>) => {
|
|
55
|
+
const [externalSelectedIds, setExternalSelectedIds] = useState<number[]>([]);
|
|
56
56
|
const columnDefs: ColDefT<ITestRow>[] = useMemo(
|
|
57
57
|
() => [
|
|
58
58
|
GridCell({
|
|
@@ -111,8 +111,8 @@ const GridPopoverEditBearingTemplate: StoryFn<typeof Grid> = (props: GridProps)
|
|
|
111
111
|
data-testid={'bearingsTestTable'}
|
|
112
112
|
{...props}
|
|
113
113
|
readOnly={false}
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
externalSelectedIds={externalSelectedIds}
|
|
115
|
+
setExternalSelectedIds={setExternalSelectedIds}
|
|
116
116
|
columnDefs={columnDefs}
|
|
117
117
|
rowData={rowData}
|
|
118
118
|
domLayout={'autoHeight'}
|
|
@@ -244,6 +244,7 @@ const GridReadOnlyTemplate: StoryFn<typeof Grid<ITestRow>> = (props: GridProps<I
|
|
|
244
244
|
<Grid
|
|
245
245
|
data-testid={'readonly'}
|
|
246
246
|
{...props}
|
|
247
|
+
enableRangeSelection={true}
|
|
247
248
|
selectable={true}
|
|
248
249
|
enableClickSelection={true}
|
|
249
250
|
enableSelectionWithoutKeys={true}
|
|
@@ -234,8 +234,8 @@ const GridKeyboardInteractionsTemplate: StoryFn<typeof Grid<ITestRow>> = (props:
|
|
|
234
234
|
);
|
|
235
235
|
};
|
|
236
236
|
|
|
237
|
-
export const
|
|
238
|
-
|
|
237
|
+
export const KeyboardInteractions: StoryFn<typeof Grid<ITestRow>> = GridKeyboardInteractionsTemplate.bind({});
|
|
238
|
+
KeyboardInteractions.play = async ({ canvasElement }) => {
|
|
239
239
|
const canvas = within(document.body);
|
|
240
240
|
|
|
241
241
|
multiEditAction.mockClear();
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
@use '../../node_modules/@linzjs/lui/dist/scss/Core' as lui;
|
|
2
|
+
|
|
3
|
+
.GridContextMenu {
|
|
4
|
+
li.szh-menu__header {
|
|
5
|
+
color: lui.$fuscous;
|
|
6
|
+
text-transform: none;
|
|
7
|
+
font-size: 14px;
|
|
8
|
+
font-weight: 600;
|
|
9
|
+
padding-left: 16px;
|
|
10
|
+
padding-right: 16px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
li.szh-menu__item {
|
|
14
|
+
padding-left: 16px;
|
|
15
|
+
padding-right: 16px;
|
|
16
|
+
|
|
17
|
+
.copyMenuMenuItem {
|
|
18
|
+
display: flex;
|
|
19
|
+
gap: 8px;
|
|
20
|
+
align-items: center;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.copyMenuMenuItem__text {
|
|
24
|
+
color: lui.$charcoal;
|
|
25
|
+
font-size: 16px;
|
|
26
|
+
font-weight: 400;
|
|
27
|
+
width: 80px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.copyMenuMenuItem__buttonDefault {
|
|
31
|
+
display: flex;
|
|
32
|
+
background: none;
|
|
33
|
+
padding: 6px 6px;
|
|
34
|
+
border: 2px solid transparent;
|
|
35
|
+
|
|
36
|
+
&.copyMenuMenuItem__buttonDefault--hidden:hover {
|
|
37
|
+
border: 2px solid lui.$charcoal;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.copyMenuMenuItem__buttonDefault--hidden .LuiIcon {
|
|
42
|
+
fill: transparent;
|
|
43
|
+
}
|
|
44
|
+
.copyMenuMenuItem__buttonDefault--hidden:hover .LuiIcon {
|
|
45
|
+
fill: lui.$fuscous;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.LuiIcon {
|
|
49
|
+
fill: lui.$fuscous;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.LuiIcon[data-icon="ic_tick"] {
|
|
53
|
+
padding-left: 4px;
|
|
54
|
+
padding-right: 4px;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
li.szh-menu__item--hover {
|
|
59
|
+
background-color: lui.$polar;
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/styles/Grid.scss
CHANGED
|
@@ -7,8 +7,12 @@
|
|
|
7
7
|
margin-right: auto;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
.ag-
|
|
11
|
-
user-select: text
|
|
10
|
+
.ag-cell:not([col-id="ag-Grid-SelectionColumn"]) {
|
|
11
|
+
user-select: text;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.rangeSelectingMultiple .ag-cell {
|
|
15
|
+
user-select: none;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
.LabelPreferencesPanelGridCellAlignCenter .ag-cell-wrapper, .LabelPreferencesPanelGridCellAlignCenter .GridCell-container {
|
|
@@ -157,3 +161,23 @@ div.ag-ltr div.ag-header-cell-resize {
|
|
|
157
161
|
font-size: lui.$base-font-size;
|
|
158
162
|
@include lui.font-regular();
|
|
159
163
|
}
|
|
164
|
+
|
|
165
|
+
div.ag-row div.ag-cell.rangeSelect {
|
|
166
|
+
background-color: rgba(72, 160, 244, 0.2);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
div.ag-row div.ag-cell.rangeSelectLeft {
|
|
170
|
+
border-left: 3px solid #48a0f4;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
div.ag-row div.ag-cell.rangeSelectRight {
|
|
174
|
+
border-right: 3px solid #48a0f4;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
div.ag-row div.ag-cell.rangeSelectTop {
|
|
178
|
+
border-top: 3px solid #48a0f4;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
div.ag-row div.ag-cell.rangeSelectBottom {
|
|
182
|
+
border-bottom: 3px solid #48a0f4;
|
|
183
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class SeededRandomForTests {
|
|
2
|
+
value: number;
|
|
3
|
+
constructor(seed: number) {
|
|
4
|
+
this.value = seed % 2147483647;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
next(maxInc?: number) {
|
|
8
|
+
this.value = (this.value * 16807) % 2147483647;
|
|
9
|
+
const result = (this.value - 1) / 2147483646;
|
|
10
|
+
if (maxInc == null) {
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
return ((result * (maxInc + 1)) | 0) % (maxInc + 1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fromArray<T>(arr: T[]): T {
|
|
17
|
+
return arr[this.next(arr.length - 1)];
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/utils/bearing.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export const bearingValueFormatter = (value: any): string => {
|
|
2
2
|
const safeValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
3
|
-
if (safeValue == null) {
|
|
3
|
+
if (safeValue == null || Number.isNaN(safeValue)) {
|
|
4
4
|
return '–';
|
|
5
5
|
}
|
|
6
6
|
return convertDDToDMS(safeValue, false);
|
|
@@ -8,7 +8,7 @@ export const bearingValueFormatter = (value: any): string => {
|
|
|
8
8
|
|
|
9
9
|
export const bearingCorrectionValueFormatter = (value: any): string => {
|
|
10
10
|
const safeValue = value;
|
|
11
|
-
if (safeValue == null) {
|
|
11
|
+
if (safeValue == null || Number.isNaN(safeValue)) {
|
|
12
12
|
return '–';
|
|
13
13
|
}
|
|
14
14
|
if (typeof safeValue === 'string') {
|