Skip to content

Commit

Permalink
feat: improved subComponents using a context (#84)
Browse files Browse the repository at this point in the history
* feat: improved subComponents using a context, fix: renamed maxlength to maxLength

* tidy up code

* Unused imports

* Unused imports, check for null on validate
  • Loading branch information
matttdawson authored Nov 8, 2022
1 parent aea622e commit ca77ffe
Show file tree
Hide file tree
Showing 14 changed files with 83 additions and 53 deletions.
32 changes: 22 additions & 10 deletions src/components/GridSubComponentTextArea.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
import { useCallback, useEffect } from "react";
import { GridSubComponentProps } from "./gridForm/GridSubComponentProps";
import { useCallback, useContext, useEffect } from "react";
import { TextInputFormatted } from "../lui/TextInputFormatted";
import { GridSubComponentContext } from "../contexts/GridSubComponentContext";

export interface GridSubComponentTextAreaProps extends GridSubComponentProps {
export interface GridSubComponentTextAreaProps {
placeholder?: string;
required?: boolean;
maxlength?: number;
maxLength?: number;
width?: string | number;
validate: (value: string) => string | null;
validate?: (value: string) => string | null;
defaultValue: string;
}

export const GridSubComponentTextArea = (props: GridSubComponentTextAreaProps): JSX.Element => {
const { value, setValue, setValid, triggerSave } = props;
const { value, setValue, setValid, triggerSave } = useContext(GridSubComponentContext);

// If is not initialised yet as it's just been created then set the default value
useEffect(() => {
if (value == null) setValue(props.defaultValue);
}, [props.defaultValue, setValue, value]);

const validate = useCallback(
(value: string) => {
(value: string | null) => {
if (value == null) return null;
// This can happen because subcomponent is invoked without type safety
if (typeof value !== "string") {
console.error("Value is not a string", value);
}
if (props.required && value.length === 0) {
return `Some text is required`;
}
if (props.maxlength && value.length > props.maxlength) {
return `Text must be no longer than ${props.maxlength} characters`;
if (props.maxLength && value.length > props.maxLength) {
return `Text must be no longer than ${props.maxLength} characters`;
}
if (props.validate) {
return props.validate(value);
Expand All @@ -29,7 +41,7 @@ export const GridSubComponentTextArea = (props: GridSubComponentTextAreaProps):
);

useEffect(() => {
setValid(validate(value) == null);
setValid(value != null && validate(value) == null);
}, [setValid, validate, value]);

return (
Expand Down
34 changes: 19 additions & 15 deletions src/components/gridForm/GridFormMultiSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { useGridPopoverHook } from "../GridPopoverHook";
import { MenuSeparatorString } from "./GridFormDropDown";
import { CellEditorCommon, CellParams } from "../GridCell";
import { ClickEvent } from "../../react-menu3/types";
import { GridSubComponentProps } from "./GridSubComponentProps";
import { GridSubComponentContext } from "contexts/GridSubComponentContext";

interface MultiFinalSelectOption<ValueType> {
value: ValueType;
Expand Down Expand Up @@ -208,20 +208,24 @@ export const GridFormMultiSelect = <RowType extends GridBaseRow, ValueType>(

{selectedValues.includes(item.value) && item.subComponent && (
<FocusableItem className={"LuiDeprecatedForms"} key={`${item.value}_subcomponent`}>
{(ref: any) =>
item.subComponent &&
item.subComponent({
ref,
value: subSelectedValues[`${item.value}`],
setValue: (value: any) => {
subSelectedValues[`${item.value}`] = value;
setSubSelectedValues({ ...subSelectedValues });
},
setValid: (valid: boolean) => {
subComponentIsValid.current[`${item.value}`] = valid;
},
triggerSave,
} as GridSubComponentProps)
{(_: any) =>
item.subComponent && (
<GridSubComponentContext.Provider
value={{
value: subSelectedValues[`${item.value}`],
setValue: (value: any) => {
subSelectedValues[`${item.value}`] = value;
setSubSelectedValues({ ...subSelectedValues });
},
setValid: (valid: boolean) => {
subComponentIsValid.current[`${item.value}`] = valid;
},
triggerSave,
}}
>
<item.subComponent />
</GridSubComponentContext.Provider>
)
}
</FocusableItem>
)}
Expand Down
6 changes: 3 additions & 3 deletions src/components/gridForm/GridFormTextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { CellEditorCommon, CellParams } from "../GridCell";
export interface GridFormTextAreaProps<RowType extends GridBaseRow> extends CellEditorCommon {
placeholder?: string;
required?: boolean;
maxlength?: number;
maxLength?: number;
width?: string | number;
validate?: (value: string) => string | null;
onSave?: (selectedRows: RowType[], value: string) => Promise<boolean>;
Expand All @@ -21,8 +21,8 @@ export const GridFormTextArea = <RowType extends GridBaseRow>(_props: GridFormTe
if (props.required && value.length == 0) {
return `Some text is required`;
}
if (props.maxlength && value.length > props.maxlength) {
return `Text must be no longer than ${props.maxlength} characters`;
if (props.maxLength && value.length > props.maxLength) {
return `Text must be no longer than ${props.maxLength} characters`;
}
if (props.validate) {
return props.validate(value);
Expand Down
6 changes: 3 additions & 3 deletions src/components/gridForm/GridFormTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export interface GridFormTextInputProps<RowType extends GridBaseRow> extends Cel
placeholder?: string;
units?: string;
required?: boolean;
maxlength?: number;
maxLength?: number;
width?: string | number;
// Return null for ok, otherwise an error string
validate?: (value: string, data: RowType) => string | null;
Expand All @@ -25,8 +25,8 @@ export const GridFormTextInput = <RowType extends GridBaseRow>(_props: GridFormT
if (props.required && trimmedValue.length == 0) {
return `Some text is required`;
}
if (props.maxlength && trimmedValue.length > props.maxlength) {
return `Text must be no longer than ${props.maxlength} characters`;
if (props.maxLength && trimmedValue.length > props.maxLength) {
return `Text must be no longer than ${props.maxLength} characters`;
}
if (props.validate) {
return props.validate(trimmedValue, props.data);
Expand Down
6 changes: 0 additions & 6 deletions src/components/gridForm/GridSubComponentProps.ts

This file was deleted.

21 changes: 21 additions & 0 deletions src/contexts/GridSubComponentContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createContext } from "react";

export interface GridSubComponentContextType {
value: any;
setValue: (value: string) => void;
setValid: (valid: boolean) => void;
triggerSave: () => Promise<void>;
}

export const GridSubComponentContext = createContext<GridSubComponentContextType>({
value: "GridSubComponentContext value no context",
setValue: () => {
console.error("GridSubComponentContext setValue no context");
},
setValid: () => {
console.error("GridSubComponentContext setValid no context");
},
triggerSave: async () => {
console.error("GridSubComponentContext triggerSave no context");
},
});
2 changes: 1 addition & 1 deletion src/stories/components/ActionButton.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useCallback, useState } from "react";
import { wait } from "../../utils/util";

export default {
title: "Components / ButtonTextWithIcon",
title: "Components / ActionButton",
component: ActionButton,
args: {},
} as ComponentMeta<typeof ActionButton>;
Expand Down
11 changes: 5 additions & 6 deletions src/stories/grid/FormTest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,22 @@ export interface IFormTestRow {

export const FormTest = <RowType extends GridBaseRow>(_props: CellEditorCommon): JSX.Element => {
const props = _props as CellParams<RowType>;
const [v1, v2, ...v3] = props.value.split(" ");
const [v1, ...v2] = props.value.split(" ");

const [nameType, setNameType] = useState(v1);
const [numba, setNumba] = useState(v2);
const [plan, setPlan] = useState(v3.join(" "));
const [numba, setNumba] = useState(v2.join(" "));

const save = useCallback(async (): Promise<boolean> => {
// eslint-disable-next-line no-console
console.log("onSave", props.selectedRows, nameType, numba, plan);
console.log("onSave", props.selectedRows, nameType, numba);

// @ts-ignore
props.selectedRows.forEach((row) => (row["name"] = [nameType, numba, plan].join(" ")));
props.selectedRows.forEach((row) => (row["name"] = [nameType, numba].join(" ")));
await wait(1000);

// Close form
return true;
}, [nameType, numba, plan, props.selectedRows]);
}, [nameType, numba, props.selectedRows]);

const [showModal, setShowModal] = useState<boolean>(false);

Expand Down
2 changes: 1 addition & 1 deletion src/stories/grid/GridPopoutBearing.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
[],
);

const [rowData, setRowData] = useState([
const [rowData] = useState([
{ id: 1000, bearing1: 1.234, bearingCorrection: 90 },
{ id: 1001, bearing1: 1.565, bearingCorrection: 240 },
{ id: 1002, bearing1: null, bearingCorrection: 355.1 },
Expand Down
2 changes: 1 addition & 1 deletion src/stories/grid/GridPopoutEditDropDown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const GridEditDropDownTemplate: ComponentStory<typeof Grid> = (props: GridProps)
[optionsFn, optionsObjects],
);

const [rowData, setRowData] = useState([
const [rowData] = useState([
{
id: 1000,
position: "Tester",
Expand Down
2 changes: 1 addition & 1 deletion src/stories/grid/GridPopoutEditGeneric.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
[],
);

const [rowData, setRowData] = useState([
const [rowData] = useState([
{ id: 1000, name: "IS IS DP12345", nameType: "IS", numba: "IX", plan: "DP 12345" },
{ id: 1001, name: "PEG V SD523", nameType: "PEG", numba: "V", plan: "SD 523" },
] as IFormTestRow[]);
Expand Down
6 changes: 3 additions & 3 deletions src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
multiEdit: true,
editorParams: {
required: true,
maxlength: 12,
maxLength: 12,
placeholder: "Enter some text...",
validate: (value: string) => {
if (value === "never") return "The value 'never' is not allowed";
Expand All @@ -88,7 +88,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
{
multiEdit: true,
editorParams: {
maxlength: 12,
maxLength: 12,
placeholder: "Enter distance...",
units: "m",
validate: (value: string) => {
Expand All @@ -115,7 +115,7 @@ const GridPopoutEditGenericTemplate: ComponentStory<typeof Grid> = (props: GridP
multiEdit: true,
editorParams: {
required: true,
maxlength: 32,
maxLength: 32,
placeholder: "Enter some text...",

validate: (value: string) => {
Expand Down
4 changes: 2 additions & 2 deletions src/stories/grid/GridPopoutEditMultiSelect.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ const GridEditMultiSelectTemplate: ComponentStory<typeof Grid> = (props: GridPro
{
value: "other",
label: "Other",
subComponent: (props) => <GridSubComponentTextArea {...props} maxlength={2} />,
subComponent: () => <GridSubComponentTextArea maxLength={2} defaultValue={""} />,
},
],
initialSelectedValues: () => ({
Expand Down Expand Up @@ -128,7 +128,7 @@ const GridEditMultiSelectTemplate: ComponentStory<typeof Grid> = (props: GridPro
];
}, []);

const [rowData, setRowData] = useState([
const [rowData] = useState([
{ id: 1000, position: "Tester", position2: "1", position3: "Tester" },
{ id: 1001, position: "Developer", position2: "2", position3: "Developer" },
] as ITestRow[]);
Expand Down
2 changes: 1 addition & 1 deletion src/stories/grid/GridReadOnly.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
[],
);

const [rowData, setRowData] = useState([
const [rowData] = useState([
{ id: 1000, position: "Tester", age: 30, desc: "Tests application", dd: "1" },
{ id: 1001, position: "Developer", age: 12, desc: "Develops application", dd: "2" },
]);
Expand Down

0 comments on commit ca77ffe

Please sign in to comment.