@linzjs/step-ag-grid 2.4.0 → 2.4.2
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.js +78 -10
- package/dist/index.js.map +1 -1
- package/dist/src/components/gridForm/GridFormDropDown.d.ts +2 -0
- package/dist/src/components/gridForm/GridFormSubComponentTextInput.d.ts +7 -0
- package/dist/src/components/gridPopoverEdit/GridPopoverMenu.d.ts +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/lui/ActionButton.d.ts +3 -3
- package/dist/step-ag-grid.esm.js +78 -11
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/gridForm/GridFormDropDown.tsx +55 -11
- package/src/components/gridForm/GridFormSubComponentTextInput.tsx +34 -0
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +3 -3
- package/src/index.ts +1 -0
- package/src/lui/ActionButton.tsx +15 -7
- package/src/stories/components/ActionButton.stories.tsx +2 -13
- package/src/stories/grid/GridPopoutEditDropDown.stories.tsx +41 -0
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +1 -11
- package/src/stories/grid/GridPopoutEditMultiSelect.stories.tsx +4 -5
- package/src/stories/grid/GridReadOnly.stories.tsx +1 -0
package/package.json
CHANGED
|
@@ -14,12 +14,14 @@ export interface GridPopoutEditDropDownSelectedItem<RowType, ValueType> {
|
|
|
14
14
|
// Note the row that was clicked on will be first
|
|
15
15
|
selectedRows: RowType[];
|
|
16
16
|
value: ValueType;
|
|
17
|
+
subComponentValue?: ValueType;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
interface FinalSelectOption<ValueType> {
|
|
20
21
|
value: ValueType;
|
|
21
22
|
label?: JSX.Element | string;
|
|
22
23
|
disabled?: boolean | string;
|
|
24
|
+
subComponent?: (props: any, ref: any) => any;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export const MenuSeparatorString = "_____MENU_SEPARATOR_____";
|
|
@@ -61,15 +63,16 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(
|
|
|
61
63
|
const [filteredValues, setFilteredValues] = useState<any[]>([]);
|
|
62
64
|
const optionsInitialising = useRef(false);
|
|
63
65
|
const [options, setOptions] = useState<FinalSelectOption<ValueType>[] | null>(null);
|
|
66
|
+
const [subComponentValues, setSubComponentValues] = useState<{ optionValue: any; subComponentValue: any }[]>([]);
|
|
64
67
|
|
|
65
68
|
const selectItemHandler = useCallback(
|
|
66
|
-
async (value: ValueType): Promise<boolean> => {
|
|
69
|
+
async (value: ValueType, subComponentValue?: ValueType): Promise<boolean> => {
|
|
67
70
|
const field = props.field;
|
|
68
71
|
return await updatingCells({ selectedRows: props.selectedRows, field }, async (selectedRows) => {
|
|
69
72
|
const hasChanged = selectedRows.some((row) => row[field as keyof RowType] !== value);
|
|
70
73
|
if (hasChanged) {
|
|
71
74
|
if (props.onSelectedItem) {
|
|
72
|
-
await props.onSelectedItem({ selectedRows, value });
|
|
75
|
+
await props.onSelectedItem({ selectedRows, value, subComponentValue });
|
|
73
76
|
} else {
|
|
74
77
|
selectedRows.forEach((row) => (row[field as keyof RowType] = value));
|
|
75
78
|
}
|
|
@@ -214,15 +217,56 @@ export const GridFormDropDown = <RowType extends GridBaseRow, ValueType>(
|
|
|
214
217
|
) : item.value === MenuHeaderString ? (
|
|
215
218
|
<MenuHeader>{item.label}</MenuHeader>
|
|
216
219
|
) : filteredValues.includes(item.value) ? null : (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
220
|
+
<>
|
|
221
|
+
{!item.subComponent ? (
|
|
222
|
+
<MenuItem
|
|
223
|
+
key={`${props.field}-${index}`}
|
|
224
|
+
disabled={!!item.disabled}
|
|
225
|
+
title={item.disabled && typeof item.disabled !== "boolean" ? item.disabled : ""}
|
|
226
|
+
value={item.value}
|
|
227
|
+
onClick={() => {
|
|
228
|
+
selectItemHandler(item.value);
|
|
229
|
+
}}
|
|
230
|
+
>
|
|
231
|
+
{item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
|
|
232
|
+
</MenuItem>
|
|
233
|
+
) : (
|
|
234
|
+
<FocusableItem className={"LuiDeprecatedForms"} key={`${props.field}-${index}_subcomponent`}>
|
|
235
|
+
{(ref: any) =>
|
|
236
|
+
item.subComponent &&
|
|
237
|
+
item.subComponent(
|
|
238
|
+
{
|
|
239
|
+
setValue: (value: any) => {
|
|
240
|
+
const localSubComponentValues = [...subComponentValues];
|
|
241
|
+
const subComponentValueIndex = localSubComponentValues.findIndex(
|
|
242
|
+
({ optionValue }) => optionValue === item.value,
|
|
243
|
+
);
|
|
244
|
+
if (subComponentValueIndex !== -1) {
|
|
245
|
+
localSubComponentValues[subComponentValueIndex].subComponentValue = value;
|
|
246
|
+
} else {
|
|
247
|
+
localSubComponentValues.push({
|
|
248
|
+
subComponentValue: value,
|
|
249
|
+
optionValue: item.value,
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
setSubComponentValues(localSubComponentValues);
|
|
253
|
+
},
|
|
254
|
+
keyDown: (key: string) => {
|
|
255
|
+
const subComponentItem = subComponentValues.find(
|
|
256
|
+
({ optionValue }) => optionValue === item.value,
|
|
257
|
+
);
|
|
258
|
+
if (key === "Enter" && subComponentItem) {
|
|
259
|
+
selectItemHandler(item.value, subComponentItem.subComponentValue);
|
|
260
|
+
ref.closeMenu();
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
ref,
|
|
265
|
+
)
|
|
266
|
+
}
|
|
267
|
+
</FocusableItem>
|
|
268
|
+
)}
|
|
269
|
+
</>
|
|
226
270
|
),
|
|
227
271
|
)}
|
|
228
272
|
</>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { TextInputFormatted } from "../../lui/TextInputFormatted";
|
|
3
|
+
|
|
4
|
+
export interface GridFormSubComponentTextInput {
|
|
5
|
+
setValue: (value: string) => void;
|
|
6
|
+
keyDown: (key: string) => void;
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const GridFormSubComponentTextInput = ({ keyDown, placeholder, setValue }: GridFormSubComponentTextInput) => {
|
|
11
|
+
const placeholderText = placeholder || "Other...";
|
|
12
|
+
const [inputValue, setInputValue] = useState("");
|
|
13
|
+
return (
|
|
14
|
+
<>
|
|
15
|
+
<TextInputFormatted
|
|
16
|
+
value={inputValue}
|
|
17
|
+
onChange={(e) => {
|
|
18
|
+
const value = e.target.value;
|
|
19
|
+
setValue(value);
|
|
20
|
+
setInputValue(value);
|
|
21
|
+
}}
|
|
22
|
+
inputProps={{
|
|
23
|
+
onKeyDown: (k: any) => keyDown(k.key),
|
|
24
|
+
placeholder: placeholderText,
|
|
25
|
+
onMouseEnter: (e) => {
|
|
26
|
+
if (document.activeElement != e.currentTarget) {
|
|
27
|
+
e.currentTarget.focus();
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
}}
|
|
31
|
+
/>
|
|
32
|
+
</>
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -12,14 +12,14 @@ import { GenericCellColDef } from "../gridRender/GridRenderGenericCell";
|
|
|
12
12
|
*/
|
|
13
13
|
export const GridPopoverMenu = <RowType extends GridBaseRow>(
|
|
14
14
|
colDef: GenericCellColDef<RowType>,
|
|
15
|
-
|
|
15
|
+
custom: GenericCellEditorProps<GridFormPopoutMenuProps<RowType>>,
|
|
16
16
|
): ColDefT<RowType> =>
|
|
17
17
|
GridCell<RowType, GridFormPopoutMenuProps<RowType>>(
|
|
18
18
|
{
|
|
19
19
|
maxWidth: 64,
|
|
20
20
|
editable: colDef.editable != null ? colDef.editable : true,
|
|
21
21
|
cellRenderer: GridRenderPopoutMenuCell,
|
|
22
|
-
cellClass:
|
|
22
|
+
cellClass: custom?.multiEdit ? GenericMultiEditCellClass : undefined,
|
|
23
23
|
...colDef,
|
|
24
24
|
cellRendererParams: {
|
|
25
25
|
// Menus open on single click, this parameter is picked up in Grid.tsx
|
|
@@ -28,6 +28,6 @@ export const GridPopoverMenu = <RowType extends GridBaseRow>(
|
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
editor: GridFormPopoutMenu,
|
|
31
|
-
...
|
|
31
|
+
...custom,
|
|
32
32
|
},
|
|
33
33
|
);
|
package/src/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ export { GridPopoverEditDropDown } from "./components/gridPopoverEdit/GridPopove
|
|
|
27
27
|
export { GridPopoverMessage } from "./components/gridPopoverEdit/GridPopoverMessage";
|
|
28
28
|
export { GridPopoverTextArea } from "./components/gridPopoverEdit/GridPopoverTextArea";
|
|
29
29
|
export { GridPopoverTextInput } from "./components/gridPopoverEdit/GridPopoverTextInput";
|
|
30
|
+
export { GridFormSubComponentTextInput } from "./components/gridForm/GridFormSubComponentTextInput";
|
|
30
31
|
export * from "./components/gridForm/GridFormDropDown";
|
|
31
32
|
export * from "./components/gridForm/GridFormMultiSelect";
|
|
32
33
|
export * from "./components/gridForm/GridFormPopoutMenu";
|
package/src/lui/ActionButton.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./ActionButton.scss";
|
|
2
2
|
|
|
3
3
|
import clsx from "clsx";
|
|
4
|
-
import { useEffect } from "react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
5
|
import { LuiButton, LuiIcon, LuiMiniSpinner } from "@linzjs/lui";
|
|
6
6
|
import { IconName } from "@linzjs/lui/dist/components/LuiIcon/LuiIcon";
|
|
7
7
|
import { usePrevious } from "./reactUtils";
|
|
@@ -15,8 +15,9 @@ export interface ActionButtonProps {
|
|
|
15
15
|
dataTestId?: string;
|
|
16
16
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "ns";
|
|
17
17
|
className?: string;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
onAction: () => Promise<void>;
|
|
19
|
+
// Used for external code to get access to whether action is in progress
|
|
20
|
+
externalSetInProgress?: () => void;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// Kept this less than one second, so I don't have issues with waitFor as it defaults to 1s
|
|
@@ -27,14 +28,15 @@ export const ActionButton = ({
|
|
|
27
28
|
name,
|
|
28
29
|
inProgressName,
|
|
29
30
|
dataTestId,
|
|
30
|
-
inProgress,
|
|
31
31
|
className,
|
|
32
32
|
title,
|
|
33
|
-
|
|
33
|
+
onAction,
|
|
34
|
+
externalSetInProgress,
|
|
34
35
|
size = "sm",
|
|
35
36
|
}: ActionButtonProps): JSX.Element => {
|
|
37
|
+
const [inProgress, setInProgress] = useState(false);
|
|
36
38
|
const lastInProgress = usePrevious(inProgress ?? false);
|
|
37
|
-
const [localInProgress, setLocalInProgress, setLocalInProgressDeferred] = useStateDeferred<boolean>(
|
|
39
|
+
const [localInProgress, setLocalInProgress, setLocalInProgressDeferred] = useStateDeferred<boolean>(inProgress);
|
|
38
40
|
|
|
39
41
|
useEffect(() => {
|
|
40
42
|
if (inProgress == lastInProgress) return;
|
|
@@ -50,7 +52,13 @@ export const ActionButton = ({
|
|
|
50
52
|
aria-label={name}
|
|
51
53
|
className={clsx("lui-button-icon", "ActionButton", className, localInProgress && "ActionButton-inProgress")}
|
|
52
54
|
size={"lg"}
|
|
53
|
-
onClick={
|
|
55
|
+
onClick={async () => {
|
|
56
|
+
setInProgress(true);
|
|
57
|
+
externalSetInProgress && setInProgress(true);
|
|
58
|
+
await onAction();
|
|
59
|
+
externalSetInProgress && setInProgress(false);
|
|
60
|
+
setInProgress(false);
|
|
61
|
+
}}
|
|
54
62
|
disabled={localInProgress}
|
|
55
63
|
>
|
|
56
64
|
{localInProgress ? (
|
|
@@ -3,7 +3,7 @@ import "@linzjs/lui/dist/fonts";
|
|
|
3
3
|
|
|
4
4
|
import { ComponentMeta, ComponentStory } from "@storybook/react/dist/ts3.9/client/preview/types-6-3";
|
|
5
5
|
import { ActionButton } from "../../lui/ActionButton";
|
|
6
|
-
import { useCallback
|
|
6
|
+
import { useCallback } from "react";
|
|
7
7
|
import { wait } from "../../utils/util";
|
|
8
8
|
|
|
9
9
|
export default {
|
|
@@ -13,21 +13,10 @@ export default {
|
|
|
13
13
|
} as ComponentMeta<typeof ActionButton>;
|
|
14
14
|
|
|
15
15
|
const ActionButtonTemplate: ComponentStory<typeof ActionButton> = () => {
|
|
16
|
-
const [inProgress, setInProgress] = useState(false);
|
|
17
16
|
const performAction = useCallback(async () => {
|
|
18
|
-
setInProgress(true);
|
|
19
17
|
await wait(1000);
|
|
20
|
-
setInProgress(false);
|
|
21
18
|
}, []);
|
|
22
|
-
return
|
|
23
|
-
<ActionButton
|
|
24
|
-
icon={"ic_add"}
|
|
25
|
-
name={"Add new row"}
|
|
26
|
-
inProgressName={"Adding..."}
|
|
27
|
-
inProgress={inProgress}
|
|
28
|
-
onClick={performAction}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
19
|
+
return <ActionButton icon={"ic_add"} name={"Add new row"} inProgressName={"Adding..."} onAction={performAction} />;
|
|
31
20
|
};
|
|
32
21
|
|
|
33
22
|
export const ActionButtonSimple = ActionButtonTemplate.bind({});
|
|
@@ -12,6 +12,7 @@ import { MenuHeaderItem, MenuSeparator, MenuSeparatorString } from "../../compon
|
|
|
12
12
|
import { wait } from "../../utils/util";
|
|
13
13
|
import { ColDefT, GridCell } from "../../components/GridCell";
|
|
14
14
|
import { GridPopoverEditDropDown } from "../../components/gridPopoverEdit/GridPopoverEditDropDown";
|
|
15
|
+
import { GridFormSubComponentTextInput } from "../../components/gridForm/GridFormSubComponentTextInput";
|
|
15
16
|
|
|
16
17
|
export default {
|
|
17
18
|
title: "Components / Grids",
|
|
@@ -40,6 +41,7 @@ interface ITestRow {
|
|
|
40
41
|
position3: string | null;
|
|
41
42
|
position4: ICode | null;
|
|
42
43
|
code: string | null;
|
|
44
|
+
sub: string | null;
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
interface ICode {
|
|
@@ -241,6 +243,43 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
241
243
|
},
|
|
242
244
|
},
|
|
243
245
|
),
|
|
246
|
+
GridPopoverEditDropDown(
|
|
247
|
+
{
|
|
248
|
+
field: "sub",
|
|
249
|
+
initialWidth: 65,
|
|
250
|
+
maxWidth: 150,
|
|
251
|
+
headerName: "Subcomponent",
|
|
252
|
+
valueGetter: (params) => params.data.sub,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
multiEdit: true,
|
|
256
|
+
editorParams: {
|
|
257
|
+
filtered: "local",
|
|
258
|
+
filterPlaceholder: "Filter this",
|
|
259
|
+
options: [
|
|
260
|
+
{
|
|
261
|
+
value: "one",
|
|
262
|
+
label: "One",
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
value: "two",
|
|
266
|
+
label: "Two",
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
value: "oth",
|
|
270
|
+
label: "Other",
|
|
271
|
+
subComponent: (props) => (
|
|
272
|
+
<GridFormSubComponentTextInput {...props} placeholder={"Subcomponent value"} />
|
|
273
|
+
),
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
onSelectedItem: async (selected) => {
|
|
277
|
+
// eslint-disable-next-line no-console
|
|
278
|
+
console.log("onSelectedItem", selected);
|
|
279
|
+
},
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
),
|
|
244
283
|
],
|
|
245
284
|
[optionsFn, optionsObjects],
|
|
246
285
|
);
|
|
@@ -253,6 +292,7 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
253
292
|
position3: "Tester",
|
|
254
293
|
position4: { code: "O1", desc: "Object One" },
|
|
255
294
|
code: "O1",
|
|
295
|
+
sub: "two",
|
|
256
296
|
},
|
|
257
297
|
{
|
|
258
298
|
id: 1001,
|
|
@@ -261,6 +301,7 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
261
301
|
position3: "Developer",
|
|
262
302
|
position4: { code: "O2", desc: "Object Two" },
|
|
263
303
|
code: "O2",
|
|
304
|
+
sub: "one",
|
|
264
305
|
},
|
|
265
306
|
] as ITestRow[]);
|
|
266
307
|
|
|
@@ -155,14 +155,10 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
|
|
|
155
155
|
[rowData],
|
|
156
156
|
);
|
|
157
157
|
|
|
158
|
-
const [inProgress, setInProgress] = useState(false);
|
|
159
|
-
|
|
160
158
|
const addRowAction = useCallback(async () => {
|
|
161
|
-
setInProgress(true);
|
|
162
159
|
await wait(1000);
|
|
163
160
|
const lastRow = rowData[rowData.length - 1];
|
|
164
161
|
setRowData([...rowData, { id: lastRow.id + 1, name: "?", nameType: "?", numba: "?", plan: "", distance: null }]);
|
|
165
|
-
setInProgress(false);
|
|
166
162
|
}, [rowData]);
|
|
167
163
|
|
|
168
164
|
return (
|
|
@@ -175,13 +171,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
|
|
|
175
171
|
rowData={rowData}
|
|
176
172
|
domLayout={"autoHeight"}
|
|
177
173
|
/>
|
|
178
|
-
<ActionButton
|
|
179
|
-
icon={"ic_add"}
|
|
180
|
-
name={"Add new row"}
|
|
181
|
-
inProgressName={"Adding..."}
|
|
182
|
-
inProgress={inProgress}
|
|
183
|
-
onClick={addRowAction}
|
|
184
|
-
/>
|
|
174
|
+
<ActionButton icon={"ic_add"} name={"Add new row"} inProgressName={"Adding..."} onAction={addRowAction} />
|
|
185
175
|
</>
|
|
186
176
|
);
|
|
187
177
|
};
|
|
@@ -13,6 +13,7 @@ import { wait } from "../../utils/util";
|
|
|
13
13
|
import { GridSubComponentTextArea } from "../../components/GridSubComponentTextArea";
|
|
14
14
|
import { ColDefT, GridCell } from "../../components/GridCell";
|
|
15
15
|
import { GridPopoutEditMultiSelect } from "../../components/gridPopoverEdit/GridPopoutEditMultiSelect";
|
|
16
|
+
import { partition } from "lodash-es";
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
title: "Components / Grids",
|
|
@@ -91,11 +92,9 @@ const GridEditMultiSelectTemplate: ComponentStory<typeof Grid> = (props: GridPro
|
|
|
91
92
|
console.log("multiSelect result", { selectedRows, selectedOptions });
|
|
92
93
|
|
|
93
94
|
await wait(1000);
|
|
94
|
-
const normalValues = selectedOptions
|
|
95
|
-
const
|
|
96
|
-
selectedRows.forEach((row) =>
|
|
97
|
-
row.position = [...normalValues, ...subValues].join(", ");
|
|
98
|
-
});
|
|
95
|
+
const [subValues, normalValues] = partition(selectedOptions, (o) => o.subComponent);
|
|
96
|
+
const newValue = [...normalValues.map((o) => o.label), ...subValues.map((o) => o.subValue)].join(", ");
|
|
97
|
+
selectedRows.forEach((row) => (row.position = newValue));
|
|
99
98
|
return true;
|
|
100
99
|
},
|
|
101
100
|
},
|
|
@@ -159,6 +159,7 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
|
|
|
159
159
|
return (
|
|
160
160
|
<Grid
|
|
161
161
|
{...props}
|
|
162
|
+
selectable={true}
|
|
162
163
|
externalSelectedItems={externalSelectedItems}
|
|
163
164
|
setExternalSelectedItems={setExternalSelectedItems}
|
|
164
165
|
columnDefs={columnDefs}
|