@linzjs/step-ag-grid 3.0.2 → 4.0.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/index.js +283 -217
- package/dist/index.js.map +1 -1
- package/dist/src/components/GridPopoverHook.d.ts +13 -1
- package/dist/src/components/gridForm/GridFormSubComponentTextArea.d.ts +11 -0
- package/dist/src/components/gridForm/GridFormSubComponentTextInput.d.ts +8 -8
- package/dist/src/components/gridForm/GridFormTextArea.d.ts +3 -4
- package/dist/src/components/gridForm/GridFormTextInput.d.ts +3 -4
- package/dist/src/index.d.ts +1 -1
- package/dist/src/lui/TextAreaInput.d.ts +4 -5
- package/dist/src/lui/TextInputFormatted.d.ts +4 -10
- package/dist/src/utils/textValidator.d.ts +6 -0
- package/dist/step-ag-grid.esm.js +283 -217
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Grid.tsx +2 -2
- package/src/components/GridCell.tsx +5 -0
- package/src/components/GridPopoverHook.tsx +79 -1
- package/src/components/gridForm/GridFormDropDown.tsx +63 -56
- package/src/components/gridForm/GridFormEditBearing.tsx +7 -8
- package/src/components/gridForm/GridFormMultiSelect.tsx +6 -10
- package/src/components/gridForm/GridFormPopoverMenu.tsx +7 -10
- package/src/components/gridForm/GridFormSubComponentTextArea.tsx +58 -0
- package/src/components/gridForm/GridFormSubComponentTextInput.tsx +48 -55
- package/src/components/gridForm/GridFormTextArea.tsx +10 -18
- package/src/components/gridForm/GridFormTextInput.tsx +12 -25
- package/src/contexts/GridPopoverContextProvider.tsx +11 -4
- package/src/index.ts +1 -1
- package/src/lui/TextAreaInput.tsx +34 -18
- package/src/lui/TextInputFormatted.tsx +19 -35
- package/src/react-menu3/components/MenuItem.tsx +5 -2
- package/src/stories/grid/FormTest.tsx +16 -3
- package/src/stories/grid/GridPopoutEditDropDown.stories.tsx +20 -17
- package/src/stories/grid/GridPopoutEditMultiSelect.stories.tsx +2 -2
- package/src/stories/grid/GridReadOnly.stories.tsx +15 -3
- package/src/utils/textValidator.ts +24 -0
- package/dist/src/components/GridSubComponentTextArea.d.ts +0 -10
- package/src/components/GridSubComponentTextArea.tsx +0 -62
|
@@ -4,37 +4,25 @@ import { useGridPopoverHook } from "../GridPopoverHook";
|
|
|
4
4
|
import { GridBaseRow } from "../Grid";
|
|
5
5
|
import { CellEditorCommon } from "../GridCell";
|
|
6
6
|
import { useGridPopoverContext } from "../../contexts/GridPopoverContext";
|
|
7
|
+
import { TextInputValidator, TextInputValidatorProps } from "../../utils/textValidator";
|
|
7
8
|
|
|
8
|
-
export interface GridFormTextInputProps<RowType extends GridBaseRow> extends CellEditorCommon {
|
|
9
|
+
export interface GridFormTextInputProps<RowType extends GridBaseRow> extends TextInputValidatorProps, CellEditorCommon {
|
|
9
10
|
placeholder?: string;
|
|
10
11
|
units?: string;
|
|
11
|
-
required?: boolean;
|
|
12
|
-
maxLength?: number;
|
|
13
12
|
width?: string | number;
|
|
14
|
-
// Return null for ok, otherwise an error string
|
|
15
|
-
validate?: (value: string, data: RowType) => string | null;
|
|
16
13
|
onSave?: (selectedRows: RowType[], value: string) => Promise<boolean>;
|
|
14
|
+
helpText?: string;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
export const GridFormTextInput = <RowType extends GridBaseRow>(props: GridFormTextInputProps<RowType>) => {
|
|
20
|
-
const { field,
|
|
18
|
+
const { field, value: initialVale } = useGridPopoverContext<RowType>();
|
|
19
|
+
|
|
20
|
+
const helpText = props.helpText ?? "Press enter or tab to save";
|
|
21
21
|
|
|
22
22
|
const initValue = initialVale == null ? "" : `${initialVale}`;
|
|
23
23
|
const [value, setValue] = useState(initValue);
|
|
24
24
|
|
|
25
|
-
const invalid = useCallback(() =>
|
|
26
|
-
const trimmedValue = value.trim();
|
|
27
|
-
if (props.required && trimmedValue.length == 0) {
|
|
28
|
-
return `Some text is required`;
|
|
29
|
-
}
|
|
30
|
-
if (props.maxLength && trimmedValue.length > props.maxLength) {
|
|
31
|
-
return `Text must be no longer than ${props.maxLength} characters`;
|
|
32
|
-
}
|
|
33
|
-
if (props.validate) {
|
|
34
|
-
return props.validate(trimmedValue, data);
|
|
35
|
-
}
|
|
36
|
-
return null;
|
|
37
|
-
}, [data, props, value]);
|
|
25
|
+
const invalid = useCallback(() => TextInputValidator(props, value), [props, value]);
|
|
38
26
|
|
|
39
27
|
const save = useCallback(
|
|
40
28
|
async (selectedRows: RowType[]): Promise<boolean> => {
|
|
@@ -57,7 +45,7 @@ export const GridFormTextInput = <RowType extends GridBaseRow>(props: GridFormTe
|
|
|
57
45
|
},
|
|
58
46
|
[invalid, value, initValue, props, field],
|
|
59
47
|
);
|
|
60
|
-
const { popoverWrapper,
|
|
48
|
+
const { popoverWrapper, onlyInputKeyboardEventHandlers } = useGridPopoverHook({ className: props.className, save });
|
|
61
49
|
|
|
62
50
|
return popoverWrapper(
|
|
63
51
|
<div style={{ display: "flex", flexDirection: "row", width: props.width ?? 240 }} className={"FormTest"}>
|
|
@@ -66,11 +54,10 @@ export const GridFormTextInput = <RowType extends GridBaseRow>(props: GridFormTe
|
|
|
66
54
|
onChange={(e) => setValue(e.target.value)}
|
|
67
55
|
error={invalid()}
|
|
68
56
|
formatted={props.units}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}}
|
|
57
|
+
style={{ width: "100%" }}
|
|
58
|
+
placeholder={props.placeholder}
|
|
59
|
+
{...onlyInputKeyboardEventHandlers}
|
|
60
|
+
helpText={helpText}
|
|
74
61
|
/>
|
|
75
62
|
</div>,
|
|
76
63
|
);
|
|
@@ -11,7 +11,7 @@ interface GridPopoverContextProps {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export const GridPopoverContextProvider = ({ props, children }: GridPopoverContextProps) => {
|
|
14
|
-
const { getSelectedRows, updatingCells } = useContext(GridContext);
|
|
14
|
+
const { getSelectedRows, updatingCells, stopEditing } = useContext(GridContext);
|
|
15
15
|
const anchorRef = useRef<Element>(props.eGridCell);
|
|
16
16
|
|
|
17
17
|
const [saving, setSaving] = useState(false);
|
|
@@ -27,9 +27,16 @@ export const GridPopoverContextProvider = ({ props, children }: GridPopoverConte
|
|
|
27
27
|
const field = props.colDef?.field ?? "";
|
|
28
28
|
|
|
29
29
|
const updateValue = useCallback(
|
|
30
|
-
async (saveFn: (selectedRows: any[]) => Promise<boolean>): Promise<boolean> =>
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
async (saveFn: (selectedRows: any[]) => Promise<boolean>): Promise<boolean> => {
|
|
31
|
+
let result = false;
|
|
32
|
+
if (!saving) {
|
|
33
|
+
result = await updatingCells({ selectedRows, field }, saveFn, setSaving);
|
|
34
|
+
if (result) stopEditing();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return result;
|
|
38
|
+
},
|
|
39
|
+
[field, saving, selectedRows, stopEditing, updatingCells],
|
|
33
40
|
);
|
|
34
41
|
|
|
35
42
|
return (
|
package/src/index.ts
CHANGED
|
@@ -39,7 +39,7 @@ export { GridHeaderSelect } from "./components/gridHeader/GridHeaderSelect";
|
|
|
39
39
|
|
|
40
40
|
export { TextAreaInput } from "./lui/TextAreaInput";
|
|
41
41
|
export { TextInputFormatted } from "./lui/TextInputFormatted";
|
|
42
|
-
export {
|
|
42
|
+
export { GridFormSubComponentTextArea } from "./components/gridForm/GridFormSubComponentTextArea";
|
|
43
43
|
|
|
44
44
|
export * from "./lui/ActionButton";
|
|
45
45
|
|
|
@@ -1,52 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InputHTMLAttributes, useState } from "react";
|
|
2
2
|
import clsx from "clsx";
|
|
3
3
|
import { LuiIcon } from "@linzjs/lui";
|
|
4
|
-
import { v4 as
|
|
4
|
+
import { v4 as uuidVersion4 } from "uuid";
|
|
5
|
+
import { omit } from "lodash-es";
|
|
5
6
|
|
|
6
7
|
export const useGenerateOrDefaultId = (idFromProps?: string) => {
|
|
7
|
-
const [id] = useState(idFromProps ? idFromProps :
|
|
8
|
+
const [id] = useState(idFromProps ? idFromProps : uuidVersion4());
|
|
8
9
|
return id;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
export interface LuiTextAreaInputProps {
|
|
12
|
+
export interface LuiTextAreaInputProps extends InputHTMLAttributes<HTMLTextAreaElement> {
|
|
13
|
+
// overrides value in base class to be string type only
|
|
14
|
+
value: string;
|
|
15
|
+
|
|
16
|
+
// Custom fields
|
|
12
17
|
label?: JSX.Element | string;
|
|
13
18
|
mandatory?: boolean;
|
|
14
|
-
|
|
15
|
-
onChange?: ChangeEventHandler<HTMLTextAreaElement>;
|
|
16
|
-
value: string;
|
|
19
|
+
helpText?: string;
|
|
17
20
|
error?: string | boolean | null;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export const TextAreaInput = (props: LuiTextAreaInputProps) => {
|
|
21
|
-
const id = useGenerateOrDefaultId(props
|
|
24
|
+
const id = useGenerateOrDefaultId(props?.id);
|
|
22
25
|
|
|
23
26
|
return (
|
|
24
27
|
<div
|
|
25
28
|
className={clsx(
|
|
26
29
|
"LuiTextAreaInput Grid-popoverContainer",
|
|
27
|
-
props.
|
|
28
|
-
props
|
|
30
|
+
props.disabled ? "isDisabled" : "",
|
|
31
|
+
props.error ? "hasError" : "",
|
|
32
|
+
props.className,
|
|
29
33
|
)}
|
|
30
34
|
>
|
|
31
35
|
<label htmlFor={id}>
|
|
32
|
-
{props.mandatory && <span className="LuiTextAreaInput-mandatory">*</span>}
|
|
33
|
-
{props.label && <span className="LuiTextAreaInput-label">{props.label}</span>}
|
|
36
|
+
{props.mandatory != null && <span className="LuiTextAreaInput-mandatory">*</span>}
|
|
37
|
+
{props.label != null && <span className="LuiTextAreaInput-label">{props.label}</span>}
|
|
34
38
|
<div className="LuiTextAreaInput-wrapper">
|
|
35
|
-
{" "}
|
|
36
39
|
{/* wrapper div used for error styling */}
|
|
37
40
|
<textarea
|
|
38
|
-
id={id}
|
|
39
|
-
value={props.value}
|
|
40
|
-
onChange={props.onChange}
|
|
41
41
|
rows={5}
|
|
42
|
-
{...props
|
|
42
|
+
{...omit(props, ["error", "value", "helpText", "formatted", "className"])}
|
|
43
|
+
id={id}
|
|
44
|
+
value={props.value ?? ""}
|
|
45
|
+
spellCheck={true}
|
|
43
46
|
onMouseEnter={(e) => {
|
|
44
47
|
if (document.activeElement != e.currentTarget) {
|
|
45
48
|
e.currentTarget.focus();
|
|
46
49
|
e.currentTarget.selectionStart = e.currentTarget.value.length;
|
|
47
50
|
}
|
|
51
|
+
props.onMouseEnter && props.onMouseEnter(e);
|
|
48
52
|
}}
|
|
49
|
-
|
|
53
|
+
>
|
|
54
|
+
{props.value}
|
|
55
|
+
</textarea>
|
|
50
56
|
</div>
|
|
51
57
|
</label>
|
|
52
58
|
|
|
@@ -57,6 +63,16 @@ export const TextAreaInput = (props: LuiTextAreaInputProps) => {
|
|
|
57
63
|
{props.error}
|
|
58
64
|
</span>
|
|
59
65
|
)}
|
|
66
|
+
|
|
67
|
+
{props.helpText && !props.error && (
|
|
68
|
+
<span
|
|
69
|
+
style={{
|
|
70
|
+
fontSize: "0.7rem",
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{props.helpText}
|
|
74
|
+
</span>
|
|
75
|
+
)}
|
|
60
76
|
</div>
|
|
61
77
|
);
|
|
62
78
|
};
|
|
@@ -1,55 +1,36 @@
|
|
|
1
1
|
import "./TextInputFormatted.scss";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
ChangeEventHandler,
|
|
5
|
-
DetailedHTMLProps,
|
|
6
|
-
FocusEventHandler,
|
|
7
|
-
InputHTMLAttributes,
|
|
8
|
-
MouseEventHandler,
|
|
9
|
-
} from "react";
|
|
3
|
+
import { DetailedHTMLProps, InputHTMLAttributes } from "react";
|
|
10
4
|
|
|
11
5
|
import clsx from "clsx";
|
|
12
6
|
import { LuiIcon } from "@linzjs/lui";
|
|
7
|
+
import { omit } from "lodash-es";
|
|
13
8
|
|
|
14
|
-
export interface LuiTextInputProps {
|
|
15
|
-
|
|
16
|
-
onFocus?: FocusEventHandler<HTMLInputElement>;
|
|
17
|
-
onClick?: MouseEventHandler<HTMLInputElement>;
|
|
18
|
-
inputProps?: DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
|
19
|
-
error?: string | boolean | null;
|
|
20
|
-
warning?: string | boolean | null;
|
|
21
|
-
|
|
22
|
-
className?: string;
|
|
9
|
+
export interface LuiTextInputProps extends DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement> {
|
|
10
|
+
// overrides value in base class to be string type only
|
|
23
11
|
value: string;
|
|
24
12
|
|
|
25
|
-
|
|
13
|
+
// Custom fields
|
|
14
|
+
helpText?: string;
|
|
15
|
+
error?: string | boolean | null;
|
|
26
16
|
formatted?: string;
|
|
27
17
|
}
|
|
28
18
|
|
|
29
19
|
export const TextInputFormatted = (props: LuiTextInputProps): JSX.Element => {
|
|
30
20
|
return (
|
|
31
|
-
<div
|
|
32
|
-
className={clsx(
|
|
33
|
-
"LuiTextInput Grid-popoverContainer",
|
|
34
|
-
props.error && "hasError",
|
|
35
|
-
props.warning && "hasWarning",
|
|
36
|
-
props.className,
|
|
37
|
-
)}
|
|
38
|
-
>
|
|
21
|
+
<div className={clsx("LuiTextInput Grid-popoverContainer", props.error && "hasError", props.className)}>
|
|
39
22
|
<span className="LuiTextInput-inputWrapper">
|
|
23
|
+
{/* wrapper div used for error styling */}
|
|
40
24
|
<input
|
|
41
25
|
type={"text"}
|
|
42
|
-
className={"LuiTextInput-input"}
|
|
43
|
-
min="0"
|
|
44
26
|
spellCheck={true}
|
|
45
27
|
defaultValue={props.value}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
onClick={props.onClick}
|
|
28
|
+
{...omit(props, ["error", "value", "helpText", "formatted", "className"])}
|
|
29
|
+
className={"LuiTextInput-input"}
|
|
49
30
|
onMouseEnter={(e) => {
|
|
50
31
|
e.currentTarget.focus();
|
|
32
|
+
props.onMouseEnter && props.onMouseEnter(e);
|
|
51
33
|
}}
|
|
52
|
-
{...props.inputProps}
|
|
53
34
|
/>
|
|
54
35
|
<span className={"LuiTextInput-formatted"}>{props.formatted}</span>
|
|
55
36
|
</span>
|
|
@@ -61,10 +42,13 @@ export const TextInputFormatted = (props: LuiTextInputProps): JSX.Element => {
|
|
|
61
42
|
</span>
|
|
62
43
|
)}
|
|
63
44
|
|
|
64
|
-
{props.
|
|
65
|
-
<span
|
|
66
|
-
|
|
67
|
-
|
|
45
|
+
{props.helpText && !props.error && (
|
|
46
|
+
<span
|
|
47
|
+
style={{
|
|
48
|
+
fontSize: "0.7rem",
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{props.helpText}
|
|
68
52
|
</span>
|
|
69
53
|
)}
|
|
70
54
|
</div>
|
|
@@ -114,7 +114,10 @@ const MenuItemFr = ({
|
|
|
114
114
|
eventHandlers.handleClick(event, isCheckBox || isRadio);
|
|
115
115
|
};
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
/**
|
|
118
|
+
* Keyboard events are triggered on up, otherwise sub-components get spaces and enters typed in them
|
|
119
|
+
*/
|
|
120
|
+
const handleKeyUp = (e: KeyboardEvent) => {
|
|
118
121
|
if (!isHovering) return;
|
|
119
122
|
|
|
120
123
|
switch (e.key) {
|
|
@@ -144,7 +147,7 @@ const MenuItemFr = ({
|
|
|
144
147
|
{
|
|
145
148
|
...restStateProps,
|
|
146
149
|
onPointerDown: setHover,
|
|
147
|
-
|
|
150
|
+
onKeyUp: handleKeyUp,
|
|
148
151
|
onClick: handleClick,
|
|
149
152
|
},
|
|
150
153
|
restProps,
|
|
@@ -39,7 +39,10 @@ export const FormTest = (props: CellEditorCommon): JSX.Element => {
|
|
|
39
39
|
|
|
40
40
|
const [showModal, setShowModal] = useState<boolean>(false);
|
|
41
41
|
|
|
42
|
-
const { popoverWrapper } = useGridPopoverHook({
|
|
42
|
+
const { popoverWrapper, firstInputKeyboardEventHandlers, lastInputKeyboardEventHandlers } = useGridPopoverHook({
|
|
43
|
+
className: props.className,
|
|
44
|
+
save,
|
|
45
|
+
});
|
|
43
46
|
|
|
44
47
|
return popoverWrapper(
|
|
45
48
|
<>
|
|
@@ -80,10 +83,20 @@ export const FormTest = (props: CellEditorCommon): JSX.Element => {
|
|
|
80
83
|
)}
|
|
81
84
|
<div style={{ display: "flex", flexDirection: "row" }} className={"FormTest Grid-popoverContainer"}>
|
|
82
85
|
<div className={"FormTest-textInput"}>
|
|
83
|
-
<LuiTextInput
|
|
86
|
+
<LuiTextInput
|
|
87
|
+
label={"Name type"}
|
|
88
|
+
value={nameType}
|
|
89
|
+
onChange={(e) => setNameType(e.target.value)}
|
|
90
|
+
inputProps={firstInputKeyboardEventHandlers}
|
|
91
|
+
/>
|
|
84
92
|
</div>
|
|
85
93
|
<div className={"FormTest-textInput"}>
|
|
86
|
-
<LuiTextInput
|
|
94
|
+
<LuiTextInput
|
|
95
|
+
label={"Number"}
|
|
96
|
+
value={numba}
|
|
97
|
+
onChange={(e) => setNumba(e.target.value)}
|
|
98
|
+
inputProps={lastInputKeyboardEventHandlers}
|
|
99
|
+
/>
|
|
87
100
|
</div>
|
|
88
101
|
<div className={"FormTest-textInput"}>
|
|
89
102
|
<LuiButton onClick={() => setShowModal(true)}>Show Modal</LuiButton>
|
|
@@ -258,26 +258,29 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
|
|
|
258
258
|
editorParams: {
|
|
259
259
|
filtered: "local",
|
|
260
260
|
filterPlaceholder: "Filter this",
|
|
261
|
-
options:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
261
|
+
options: () => {
|
|
262
|
+
return [
|
|
263
|
+
{
|
|
264
|
+
value: "one",
|
|
265
|
+
label: "One",
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
value: "two",
|
|
269
|
+
label: "Two",
|
|
270
|
+
},
|
|
271
|
+
{
|
|
272
|
+
value: "oth",
|
|
273
|
+
label: "Other",
|
|
274
|
+
subComponent: () => (
|
|
275
|
+
<GridFormSubComponentTextInput placeholder={"Other..."} defaultValue={""} required={true} />
|
|
276
|
+
),
|
|
277
|
+
},
|
|
278
|
+
];
|
|
279
|
+
},
|
|
278
280
|
onSelectedItem: async (selected) => {
|
|
279
281
|
// eslint-disable-next-line no-console
|
|
280
282
|
console.log("onSelectedItem", selected);
|
|
283
|
+
selected.selectedRows.forEach((row) => (row.sub = selected.subComponentValue ?? selected.value));
|
|
281
284
|
},
|
|
282
285
|
},
|
|
283
286
|
},
|
|
@@ -10,7 +10,7 @@ import { Grid, GridProps } from "../../components/Grid";
|
|
|
10
10
|
import { useMemo, useState } from "react";
|
|
11
11
|
import { MenuSeparator } from "../../components/gridForm/GridFormDropDown";
|
|
12
12
|
import { wait } from "../../utils/util";
|
|
13
|
-
import {
|
|
13
|
+
import { GridFormSubComponentTextArea } from "../../components/gridForm/GridFormSubComponentTextArea";
|
|
14
14
|
import { ColDefT, GridCell } from "../../components/GridCell";
|
|
15
15
|
import { GridPopoutEditMultiSelect } from "../../components/gridPopoverEdit/GridPopoutEditMultiSelect";
|
|
16
16
|
import { partition } from "lodash-es";
|
|
@@ -81,7 +81,7 @@ const GridEditMultiSelectTemplate: ComponentStory<typeof Grid> = (props: GridPro
|
|
|
81
81
|
{
|
|
82
82
|
value: "other",
|
|
83
83
|
label: "Other",
|
|
84
|
-
subComponent: () => <
|
|
84
|
+
subComponent: () => <GridFormSubComponentTextArea maxLength={5} defaultValue={""} />,
|
|
85
85
|
},
|
|
86
86
|
],
|
|
87
87
|
initialSelectedValues: () => ({
|
|
@@ -12,8 +12,9 @@ import { wait } from "../../utils/util";
|
|
|
12
12
|
import { GridPopoverMenu } from "../../components/gridPopoverEdit/GridPopoverMenu";
|
|
13
13
|
import { ColDefT, GridCell } from "../../components/GridCell";
|
|
14
14
|
import { GridPopoverMessage } from "../../components/gridPopoverEdit/GridPopoverMessage";
|
|
15
|
-
import { GridSubComponentTextArea } from "../../components/GridSubComponentTextArea";
|
|
16
15
|
import { MenuOption } from "../../components/gridForm/GridFormPopoverMenu";
|
|
16
|
+
import { GridFormSubComponentTextInput } from "../../components/gridForm/GridFormSubComponentTextInput";
|
|
17
|
+
import { GridFormSubComponentTextArea } from "../../components/gridForm/GridFormSubComponentTextArea";
|
|
17
18
|
|
|
18
19
|
export default {
|
|
19
20
|
title: "Components / Grids",
|
|
@@ -129,13 +130,23 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
|
|
|
129
130
|
supportsMultiEdit: true,
|
|
130
131
|
},
|
|
131
132
|
{
|
|
132
|
-
label: "Other",
|
|
133
|
+
label: "Other (TextInput)",
|
|
133
134
|
supportsMultiEdit: true,
|
|
134
135
|
action: (_, menuOptionResult) => {
|
|
135
136
|
alert(`Sub selected value was ${JSON.stringify(menuOptionResult.subValue)}`);
|
|
136
137
|
},
|
|
137
138
|
subComponent: () => (
|
|
138
|
-
<
|
|
139
|
+
<GridFormSubComponentTextInput placeholder={"Other"} maxLength={2} required defaultValue={""} />
|
|
140
|
+
),
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
label: "Other (TextArea)",
|
|
144
|
+
supportsMultiEdit: true,
|
|
145
|
+
action: (_, menuOptionResult) => {
|
|
146
|
+
alert(`Sub selected value was ${JSON.stringify(menuOptionResult.subValue)}`);
|
|
147
|
+
},
|
|
148
|
+
subComponent: () => (
|
|
149
|
+
<GridFormSubComponentTextArea placeholder={"Other"} maxLength={2} required defaultValue={""} />
|
|
139
150
|
),
|
|
140
151
|
},
|
|
141
152
|
] as MenuOption<ITestRow>[];
|
|
@@ -162,6 +173,7 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
|
|
|
162
173
|
const [rowData] = useState([
|
|
163
174
|
{ id: 1000, position: "Tester", age: 30, desc: "Tests application", dd: "1" },
|
|
164
175
|
{ id: 1001, position: "Developer", age: 12, desc: "Develops application", dd: "2" },
|
|
176
|
+
{ id: 1002, position: "Manager", age: 65, desc: "Manages", dd: "3" },
|
|
165
177
|
]);
|
|
166
178
|
|
|
167
179
|
return (
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface TextInputValidatorProps {
|
|
2
|
+
required?: boolean;
|
|
3
|
+
maxLength?: number;
|
|
4
|
+
validate?: (value: string) => string | null;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const TextInputValidator = (props: TextInputValidatorProps, value: string | null) => {
|
|
8
|
+
if (value == null) return null;
|
|
9
|
+
|
|
10
|
+
// This can happen because subcomponent is invoked without type safety
|
|
11
|
+
if (typeof value !== "string") {
|
|
12
|
+
console.error("Value is not a string", value);
|
|
13
|
+
}
|
|
14
|
+
if (props.required && value.length === 0) {
|
|
15
|
+
return `Some text is required`;
|
|
16
|
+
}
|
|
17
|
+
if (props.maxLength && value.length > props.maxLength) {
|
|
18
|
+
return `Text must be no longer than ${props.maxLength} characters`;
|
|
19
|
+
}
|
|
20
|
+
if (props.validate) {
|
|
21
|
+
return props.validate(value);
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
};
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/// <reference types="react" />
|
|
2
|
-
export interface GridSubComponentTextAreaProps {
|
|
3
|
-
placeholder?: string;
|
|
4
|
-
required?: boolean;
|
|
5
|
-
maxLength?: number;
|
|
6
|
-
width?: string | number;
|
|
7
|
-
validate?: (value: string) => string | null;
|
|
8
|
-
defaultValue: string;
|
|
9
|
-
}
|
|
10
|
-
export declare const GridSubComponentTextArea: (props: GridSubComponentTextAreaProps) => JSX.Element;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { useCallback, useContext, useEffect } from "react";
|
|
2
|
-
import { TextInputFormatted } from "../lui/TextInputFormatted";
|
|
3
|
-
import { GridSubComponentContext } from "../contexts/GridSubComponentContext";
|
|
4
|
-
|
|
5
|
-
export interface GridSubComponentTextAreaProps {
|
|
6
|
-
placeholder?: string;
|
|
7
|
-
required?: boolean;
|
|
8
|
-
maxLength?: number;
|
|
9
|
-
width?: string | number;
|
|
10
|
-
validate?: (value: string) => string | null;
|
|
11
|
-
defaultValue: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const GridSubComponentTextArea = (props: GridSubComponentTextAreaProps): JSX.Element => {
|
|
15
|
-
const { value, setValue, setValid, triggerSave } = useContext(GridSubComponentContext);
|
|
16
|
-
|
|
17
|
-
// If is not initialised yet as it's just been created then set the default value
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (value == null) setValue(props.defaultValue);
|
|
20
|
-
}, [props.defaultValue, setValue, value]);
|
|
21
|
-
|
|
22
|
-
const validate = useCallback(
|
|
23
|
-
(value: string | null) => {
|
|
24
|
-
if (value == null) return null;
|
|
25
|
-
// This can happen because subcomponent is invoked without type safety
|
|
26
|
-
if (typeof value !== "string") {
|
|
27
|
-
console.error("Value is not a string", value);
|
|
28
|
-
}
|
|
29
|
-
if (props.required && value.length === 0) {
|
|
30
|
-
return `Some text is required`;
|
|
31
|
-
}
|
|
32
|
-
if (props.maxLength && value.length > props.maxLength) {
|
|
33
|
-
return `Text must be no longer than ${props.maxLength} characters`;
|
|
34
|
-
}
|
|
35
|
-
if (props.validate) {
|
|
36
|
-
return props.validate(value);
|
|
37
|
-
}
|
|
38
|
-
return null;
|
|
39
|
-
},
|
|
40
|
-
[props],
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
useEffect(() => {
|
|
44
|
-
setValid(value != null && validate(value) == null);
|
|
45
|
-
}, [setValid, validate, value]);
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<div className={"FreeTextInput LuiDeprecatedForms"}>
|
|
49
|
-
<TextInputFormatted
|
|
50
|
-
className={"free-text-input"}
|
|
51
|
-
value={value}
|
|
52
|
-
onChange={(e) => setValue(e.target.value)}
|
|
53
|
-
error={validate(value)}
|
|
54
|
-
inputProps={{
|
|
55
|
-
autoFocus: true,
|
|
56
|
-
placeholder: props.placeholder,
|
|
57
|
-
onKeyDown: async (e) => e.key === "Enter" && triggerSave().then(),
|
|
58
|
-
}}
|
|
59
|
-
/>
|
|
60
|
-
</div>
|
|
61
|
-
);
|
|
62
|
-
};
|